├── ajax ├── dojo │ ├── content.php │ ├── dojo.js │ ├── json.php │ ├── submit.php │ ├── submitform.php │ └── testdojo.html ├── jquery │ ├── ajaxback.php │ ├── ajaxload.php │ ├── ajaxtest.html │ ├── fakepost.php │ ├── jquery.js │ ├── json.php │ ├── serialize.html │ ├── submit.php │ └── submitform.php └── mootools │ ├── ajaxload.php │ ├── gets.php │ ├── json.php │ ├── mootools-more-1.4.0.1.js │ ├── mootools.js │ ├── submitform.php │ ├── test.html │ └── test.php ├── ebay_finding_api ├── class.ebay.php └── ebay_finding_test.php ├── extending_laravels_validation_class └── application │ ├── config │ └── application.php │ ├── language │ └── en │ │ └── validation.php │ └── libraries │ └── validator.php ├── getting_started_with_amazon_product_api ├── amazon_product_api_class.php ├── amazon_product_api_signed_request.php └── index.php ├── getting_started_with_freebase_api ├── class.freebase.php └── test.freebase.php ├── gmaps ├── index.php ├── js │ └── jquery172.js ├── places_config.php ├── save_place.php └── sql │ └── db.sql ├── mustache ├── data.php ├── data2.php ├── jquery171.js ├── mustache.js └── test.html ├── readme.md ├── registration_system_using_knockoutjs ├── refresher.css ├── refresher.html └── refresher_save.php ├── storejs ├── jquery171.js ├── store.js └── teststore.html ├── sugarjs ├── sugar.js └── sugartest.html └── zam ├── js └── main.js ├── libs └── twitteroauth │ ├── OAuth.php │ └── twitteroauth.php ├── phpunit.xml ├── tests ├── bootstrap.php └── zam │ └── zamTest.php ├── zam-options.php ├── zam-tweets-widget.php └── zam.php /ajax/dojo/content.php: -------------------------------------------------------------------------------- 1 | names; //that's why we access them like accesing methods or properties from real objects like this 7 | $languages = $obj->languages; 8 | echo "

Names:

"; 9 | //we then loop through the items like how were used to with arrays 10 | foreach($names as $row){ 11 | echo "
  • ".$row."
  • "; 12 | } 13 | 14 | echo "

    Languages:

    "; 15 | foreach($languages as $row){ 16 | echo "
  • ".$row."
  • "; 17 | } 18 | ?> -------------------------------------------------------------------------------- /ajax/dojo/json.php: -------------------------------------------------------------------------------- 1 | ['smashing magazine', 'codrops', 'sixrevisions', 'nettuts', 'coding horror'], 4 | 'people'=>['john resig', 'jeffrey way', 'chris coyier', 'jamison dance'] 5 | ]; 6 | $json_things = json_encode($things); 7 | echo $json_things; 8 | ?> -------------------------------------------------------------------------------- /ajax/dojo/submit.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ajax/dojo/submitform.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ajax/dojo/testdojo.html: -------------------------------------------------------------------------------- 1 |
    2 |

    3 | 4 | 5 |

    6 | 7 |

    8 | 9 | 10 |

    11 |
    12 | 13 |
    14 |

    15 | 16 | 17 |

    18 | 19 |

    20 | 21 | 22 |

    23 | 24 |

    25 | 26 | 27 |

    28 |
    29 |
    30 | 31 | -------------------------------------------------------------------------------- /ajax/jquery/ajaxback.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ajax/jquery/ajaxload.php: -------------------------------------------------------------------------------- 1 |

    2 | 3 |

    4 | 7 |
  • 8 | -------------------------------------------------------------------------------- /ajax/jquery/ajaxtest.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    4 | 5 | 6 |

    7 | 8 |

    9 | 10 | 11 |

    12 |
    13 | 14 |
    15 |

    16 | 17 | 18 |

    19 | 20 |

    21 | 22 | 23 |

    24 | 25 |

    26 | 27 | 28 |

    29 |
    30 | 31 | -------------------------------------------------------------------------------- /ajax/jquery/fakepost.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ajax/jquery/jquery.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anchetaWern/tutorials/5259e6864d7f5a0a02bbb1f8158dbac90ead065d/ajax/jquery/jquery.js -------------------------------------------------------------------------------- /ajax/jquery/json.php: -------------------------------------------------------------------------------- 1 | ['smashing magazine', 'codrops', 'sixrevisions', 'nettuts', 'coding horror'], 4 | 'people'=>['john resig', 'jeffrey way', 'chris coyier', 'paul irish'] 5 | ]; 6 | $json_things = json_encode($things); 7 | echo $json_things; 8 | ?> -------------------------------------------------------------------------------- /ajax/jquery/serialize.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | 6 |
    7 | 8 | -------------------------------------------------------------------------------- /ajax/jquery/submit.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ajax/jquery/submitform.php: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /ajax/mootools/ajaxload.php: -------------------------------------------------------------------------------- 1 |

    I'm loaded via ajax

    -------------------------------------------------------------------------------- /ajax/mootools/gets.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ajax/mootools/json.php: -------------------------------------------------------------------------------- 1 | ['smashing magazine', 'codrops', 'sixrevisions', 'nettuts', 'coding horror'], 4 | 'people'=>['john resig', 'jeffrey way', 'chris coyier', 'jamison dance'] 5 | ]; 6 | $json_things = json_encode($things); 7 | echo $json_things; 8 | ?> -------------------------------------------------------------------------------- /ajax/mootools/mootools-more-1.4.0.1.js: -------------------------------------------------------------------------------- 1 | // MooTools: the javascript framework. 2 | // Load this file's selection again by visiting: http://mootools.net/more/512fd1917d2d71d8f22608a7133fe249 3 | // Or build this file again with packager using: packager build More/String.QueryString 4 | /* 5 | --- 6 | 7 | script: More.js 8 | 9 | name: More 10 | 11 | description: MooTools More 12 | 13 | license: MIT-style license 14 | 15 | authors: 16 | - Guillermo Rauch 17 | - Thomas Aylott 18 | - Scott Kyle 19 | - Arian Stolwijk 20 | - Tim Wienk 21 | - Christoph Pojer 22 | - Aaron Newton 23 | - Jacob Thornton 24 | 25 | requires: 26 | - Core/MooTools 27 | 28 | provides: [MooTools.More] 29 | 30 | ... 31 | */ 32 | 33 | MooTools.More = { 34 | 'version': '1.4.0.1', 35 | 'build': 'a4244edf2aa97ac8a196fc96082dd35af1abab87' 36 | }; 37 | 38 | 39 | /* 40 | --- 41 | 42 | script: String.QueryString.js 43 | 44 | name: String.QueryString 45 | 46 | description: Methods for dealing with URI query strings. 47 | 48 | license: MIT-style license 49 | 50 | authors: 51 | - Sebastian Markbåge 52 | - Aaron Newton 53 | - Lennart Pilon 54 | - Valerio Proietti 55 | 56 | requires: 57 | - Core/Array 58 | - Core/String 59 | - /MooTools.More 60 | 61 | provides: [String.QueryString] 62 | 63 | ... 64 | */ 65 | 66 | String.implement({ 67 | 68 | parseQueryString: function(decodeKeys, decodeValues){ 69 | if (decodeKeys == null) decodeKeys = true; 70 | if (decodeValues == null) decodeValues = true; 71 | 72 | var vars = this.split(/[&;]/), 73 | object = {}; 74 | if (!vars.length) return object; 75 | 76 | vars.each(function(val){ 77 | var index = val.indexOf('=') + 1, 78 | value = index ? val.substr(index) : '', 79 | keys = index ? val.substr(0, index - 1).match(/([^\]\[]+|(\B)(?=\]))/g) : [val], 80 | obj = object; 81 | if (!keys) return; 82 | if (decodeValues) value = decodeURIComponent(value); 83 | keys.each(function(key, i){ 84 | if (decodeKeys) key = decodeURIComponent(key); 85 | var current = obj[key]; 86 | 87 | if (i < keys.length - 1) obj = obj[key] = current || {}; 88 | else if (typeOf(current) == 'array') current.push(value); 89 | else obj[key] = current != null ? [current, value] : value; 90 | }); 91 | }); 92 | 93 | return object; 94 | }, 95 | 96 | cleanQueryString: function(method){ 97 | return this.split('&').filter(function(val){ 98 | var index = val.indexOf('='), 99 | key = index < 0 ? '' : val.substr(0, index), 100 | value = val.substr(index + 1); 101 | 102 | return method ? method.call(null, key, value) : (value || value === 0); 103 | }).join('&'); 104 | } 105 | 106 | }); 107 | 108 | -------------------------------------------------------------------------------- /ajax/mootools/submitform.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ajax/mootools/test.html: -------------------------------------------------------------------------------- 1 |
    fsfsfsffsf
    2 |
    3 |

    4 | 5 | 6 |

    7 | 8 |

    9 | 10 | 11 |

    12 |
    13 | 14 |
    15 |

    16 | 17 | 18 |

    19 | 20 |

    21 | 22 | 23 |

    24 | 25 |

    26 | 27 | 28 |

    29 |
    30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ajax/mootools/test.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ebay_finding_api/class.ebay.php: -------------------------------------------------------------------------------- 1 | app_id = $app_id; 13 | $this->global_id = $global_id; 14 | } 15 | 16 | public function findItems($keyword = '', $limit = 2){ 17 | 18 | $url = $this->url . '?'; 19 | $url .= 'operation-name=findItemsByKeywords'; 20 | $url .= '&service-version=' . $this->version; 21 | $url .= '&keywords=' . urlencode($keyword); 22 | $url .= '&paginationInput.entriesPerPage=' . $limit; 23 | 24 | $url .= '&security-appname='. $this->app_id; 25 | $url .= '&response-data-format=' . $this->format; 26 | 27 | return json_decode(file_get_contents($url), true); 28 | } 29 | 30 | public function findItemsAdvanced($keyword = '', $item_sort = 'BestMatch', $item_type = 'FixedPricedItem', $min_price = '0', $max_price = '9999999', $limit = 10){ 31 | 32 | $url = $this->url . '?'; 33 | $url .= 'operation-name=findItemsAdvanced'; 34 | $url .= '&service-version=' . $this->version; 35 | $url .= '&global-id=' . $this->global_id; 36 | $url .= '&keywords=' . urlencode($keyword); 37 | 38 | $url .= '&sortOrder=BestMatch'; 39 | $url .= '&itemFilter(0).name=ListingType'; 40 | $url .= '&itemFilter(0).value=FixedPrice'; 41 | $url .= '&itemFilter(1).name=MinPrice'; 42 | $url .= '&itemFilter(1).value=' . $min_price; 43 | $url .= '&itemFilter(2).name=MaxPrice'; 44 | $url .= '&itemFilter(2).value=' . $max_price; 45 | $url .= '&paginationInput.entriesPerPage=' . $limit; 46 | $url .= '&descriptionSearch=false'; 47 | 48 | $url .= '&security-appname='. $this->app_id; 49 | $url .= '&response-data-format=' . $this->format; 50 | 51 | return json_decode(file_get_contents($url), true); 52 | } 53 | 54 | public function sortOrders(){ 55 | $sort_orders = array( 56 | 'BestMatch' => 'Best Match', 57 | 'BidCountFewest' => 'Bid Count Fewest', 58 | 'BidCountMost' => 'Bid Count Most', 59 | 'CountryAscending' => 'Country Ascending', 60 | 'CountryDescending' => 'Country Descending', 61 | 'CurrentPriceHighest' => 'Current Highest Price', 62 | 'DistanceNearest' => 'Nearest Distance', 63 | 'EndTimeSoonest' => 'End Time Soonest', 64 | 'PricePlusShippingHighest' => 'Price Plus Shipping Highest', 65 | 'PricePlusShippingLowest' => 'Price Plus Shipping Lowest', 66 | 'StartTimeNewest' => 'Start Time Newest' 67 | ); 68 | 69 | return $sort_orders; 70 | } 71 | } 72 | ?> -------------------------------------------------------------------------------- /ebay_finding_api/ebay_finding_test.php: -------------------------------------------------------------------------------- 1 | sortOrders(); 6 | ?> 7 | 8 |
    9 | 10 | 19 | 20 |
    21 | 22 | findItemsAdvanced($_POST['search'], $_POST['sort']); 27 | $item_count = $results['findItemsAdvancedResponse'][0]['searchResult'][0]['@count']; 28 | 29 | 30 | if($item_count > 0){ 31 | $items = $results['findItemsAdvancedResponse'][0]['searchResult'][0]['item']; 32 | 33 | foreach($items as $i){ 34 | ?> 35 |
  • 36 |
    37 | 38 |
    39 |
    40 | <?php echo $i['title']; ?> 41 |
    42 |
    43 | 44 | 45 |
    46 |
  • 47 | -------------------------------------------------------------------------------- /extending_laravels_validation_class/application/config/application.php: -------------------------------------------------------------------------------- 1 | '', 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Asset URL 21 | |-------------------------------------------------------------------------- 22 | | 23 | | The base URL used for your application's asset files. This is useful if 24 | | you are serving your assets through a different server or a CDN. If it 25 | | is not set, we'll default to the application URL above. 26 | | 27 | */ 28 | 29 | 'asset_url' => '', 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Application Index 34 | |-------------------------------------------------------------------------- 35 | | 36 | | If you are including the "index.php" in your URLs, you can ignore this. 37 | | However, if you are using mod_rewrite to get cleaner URLs, just set 38 | | this option to an empty string and we'll take care of the rest. 39 | | 40 | */ 41 | 42 | 'index' => '', 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Application Key 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This key is used by the encryption and cookie classes to generate secure 50 | | encrypted strings and hashes. It is extremely important that this key 51 | | remains secret and it should not be shared with anyone. Make it about 32 52 | | characters of random gibberish. 53 | | 54 | */ 55 | 56 | 'key' => 'B8NH7pL6NtQgvxCcbo4lfpn81FIT1WOL', 57 | 58 | /* 59 | |-------------------------------------------------------------------------- 60 | | Profiler Toolbar 61 | |-------------------------------------------------------------------------- 62 | | 63 | | Laravel includes a beautiful profiler toolbar that gives you a heads 64 | | up display of the queries and logs performed by your application. 65 | | This is wonderful for development, but, of course, you should 66 | | disable the toolbar for production applications. 67 | | 68 | */ 69 | 70 | 'profiler' => true, 71 | 72 | /* 73 | |-------------------------------------------------------------------------- 74 | | Application Character Encoding 75 | |-------------------------------------------------------------------------- 76 | | 77 | | The default character encoding used by your application. This encoding 78 | | will be used by the Str, Text, Form, and any other classes that need 79 | | to know what type of encoding to use for your awesome application. 80 | | 81 | */ 82 | 83 | 'encoding' => 'UTF-8', 84 | 85 | /* 86 | |-------------------------------------------------------------------------- 87 | | Default Application Language 88 | |-------------------------------------------------------------------------- 89 | | 90 | | The default language of your application. This language will be used by 91 | | Lang library as the default language when doing string localization. 92 | | 93 | */ 94 | 95 | 'language' => 'en', 96 | 97 | /* 98 | |-------------------------------------------------------------------------- 99 | | Supported Languages 100 | |-------------------------------------------------------------------------- 101 | | 102 | | These languages may also be supported by your application. If a request 103 | | enters your application with a URI beginning with one of these values 104 | | the default language will automatically be set to that language. 105 | | 106 | */ 107 | 108 | 'languages' => array(), 109 | 110 | /* 111 | |-------------------------------------------------------------------------- 112 | | SSL Link Generation 113 | |-------------------------------------------------------------------------- 114 | | 115 | | Many sites use SSL to protect their users' data. However, you may not be 116 | | able to use SSL on your development machine, meaning all HTTPS will be 117 | | broken during development. 118 | | 119 | | For this reason, you may wish to disable the generation of HTTPS links 120 | | throughout your application. This option does just that. All attempts 121 | | to generate HTTPS links will generate regular HTTP links instead. 122 | | 123 | */ 124 | 125 | 'ssl' => true, 126 | 127 | /* 128 | |-------------------------------------------------------------------------- 129 | | Application Timezone 130 | |-------------------------------------------------------------------------- 131 | | 132 | | The default timezone of your application. The timezone will be used when 133 | | Laravel needs a date, such as when writing to a log file or travelling 134 | | to a distant star at warp speed. 135 | | 136 | */ 137 | 138 | 'timezone' => 'UTC', 139 | 140 | /* 141 | |-------------------------------------------------------------------------- 142 | | Class Aliases 143 | |-------------------------------------------------------------------------- 144 | | 145 | | Here, you can specify any class aliases that you would like registered 146 | | when Laravel loads. Aliases are lazy-loaded, so feel free to add! 147 | | 148 | | Aliases make it more convenient to use namespaced classes. Instead of 149 | | referring to the class using its full namespace, you may simply use 150 | | the alias defined here. 151 | | 152 | */ 153 | 154 | 'aliases' => array( 155 | 'Auth' => 'Laravel\\Auth', 156 | 'Authenticator' => 'Laravel\\Auth\\Drivers\\Driver', 157 | 'Asset' => 'Laravel\\Asset', 158 | 'Autoloader' => 'Laravel\\Autoloader', 159 | 'Blade' => 'Laravel\\Blade', 160 | 'Bundle' => 'Laravel\\Bundle', 161 | 'Cache' => 'Laravel\\Cache', 162 | 'Config' => 'Laravel\\Config', 163 | 'Controller' => 'Laravel\\Routing\\Controller', 164 | 'Cookie' => 'Laravel\\Cookie', 165 | 'Crypter' => 'Laravel\\Crypter', 166 | 'DB' => 'Laravel\\Database', 167 | 'Eloquent' => 'Laravel\\Database\\Eloquent\\Model', 168 | 'Event' => 'Laravel\\Event', 169 | 'File' => 'Laravel\\File', 170 | 'Filter' => 'Laravel\\Routing\\Filter', 171 | 'Form' => 'Laravel\\Form', 172 | 'Hash' => 'Laravel\\Hash', 173 | 'HTML' => 'Laravel\\HTML', 174 | 'Input' => 'Laravel\\Input', 175 | 'IoC' => 'Laravel\\IoC', 176 | 'Lang' => 'Laravel\\Lang', 177 | 'Log' => 'Laravel\\Log', 178 | 'Memcached' => 'Laravel\\Memcached', 179 | 'Paginator' => 'Laravel\\Paginator', 180 | 'Profiler' => 'Laravel\\Profiling\\Profiler', 181 | 'URL' => 'Laravel\\URL', 182 | 'Redirect' => 'Laravel\\Redirect', 183 | 'Redis' => 'Laravel\\Redis', 184 | 'Request' => 'Laravel\\Request', 185 | 'Response' => 'Laravel\\Response', 186 | 'Route' => 'Laravel\\Routing\\Route', 187 | 'Router' => 'Laravel\\Routing\\Router', 188 | 'Schema' => 'Laravel\\Database\\Schema', 189 | 'Section' => 'Laravel\\Section', 190 | 'Session' => 'Laravel\\Session', 191 | 'Str' => 'Laravel\\Str', 192 | 'Task' => 'Laravel\\CLI\\Tasks\\Task', 193 | 'URI' => 'Laravel\\URI', 194 | 'View' => 'Laravel\\View', 195 | ), 196 | 197 | ); 198 | -------------------------------------------------------------------------------- /extending_laravels_validation_class/application/language/en/validation.php: -------------------------------------------------------------------------------- 1 | "The :attribute must be accepted.", 22 | "active_url" => "The :attribute is not a valid URL.", 23 | "after" => "The :attribute must be a date after :date.", 24 | "alpha" => "The :attribute may only contain letters.", 25 | "alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.", 26 | "alpha_num" => "The :attribute may only contain letters and numbers.", 27 | "array" => "The :attribute must have selected elements.", 28 | "before" => "The :attribute must be a date before :date.", 29 | "between" => array( 30 | "numeric" => "The :attribute must be between :min - :max.", 31 | "file" => "The :attribute must be between :min - :max kilobytes.", 32 | "string" => "The :attribute must be between :min - :max characters.", 33 | ), 34 | "confirmed" => "The :attribute confirmation does not match.", 35 | "count" => "The :attribute must have exactly :count selected elements.", 36 | "countbetween" => "The :attribute must have between :min and :max selected elements.", 37 | "countmax" => "The :attribute must have less than :max selected elements.", 38 | "countmin" => "The :attribute must have at least :min selected elements.", 39 | "different" => "The :attribute and :other must be different.", 40 | "email" => "The :attribute format is invalid.", 41 | "exists" => "The selected :attribute is invalid.", 42 | "image" => "The :attribute must be an image.", 43 | "in" => "The selected :attribute is invalid.", 44 | "integer" => "The :attribute must be an integer.", 45 | "ip" => "The :attribute must be a valid IP address.", 46 | "match" => "The :attribute format is invalid.", 47 | "max" => array( 48 | "numeric" => "The :attribute must be less than :max.", 49 | "file" => "The :attribute must be less than :max kilobytes.", 50 | "string" => "The :attribute must be less than :max characters.", 51 | ), 52 | "mimes" => "The :attribute must be a file of type: :values.", 53 | "min" => array( 54 | "numeric" => "The :attribute must be at least :min.", 55 | "file" => "The :attribute must be at least :min kilobytes.", 56 | "string" => "The :attribute must be at least :min characters.", 57 | ), 58 | "not_in" => "The selected :attribute is invalid.", 59 | "numeric" => "The :attribute must be a number.", 60 | "required" => "The :attribute field is required.", 61 | "same" => "The :attribute and :other must match.", 62 | "size" => array( 63 | "numeric" => "The :attribute must be :size.", 64 | "file" => "The :attribute must be :size kilobyte.", 65 | "string" => "The :attribute must be :size characters.", 66 | ), 67 | "unique" => "The :attribute has already been taken.", 68 | "url" => "The :attribute format is invalid.", 69 | "date" => "The :attribute is invalid date", 70 | "arrayfull" => "The :attribute contains empty values", 71 | "arrayunique" => "The :attribute contains duplicate values", 72 | "arraynumeric" => "The :attribute contains non-numeric values", 73 | 74 | /* 75 | |-------------------------------------------------------------------------- 76 | | Custom Validation Language Lines 77 | |-------------------------------------------------------------------------- 78 | | 79 | | Here you may specify custom validation messages for attributes using the 80 | | convention "attribute_rule" to name the lines. This helps keep your 81 | | custom validation clean and tidy. 82 | | 83 | | So, say you want to use a custom validation message when validating that 84 | | the "email" attribute is unique. Just add "email_unique" to this array 85 | | with your custom message. The Validator will handle the rest! 86 | | 87 | */ 88 | 89 | 'custom' => array(), 90 | 91 | /* 92 | |-------------------------------------------------------------------------- 93 | | Validation Attributes 94 | |-------------------------------------------------------------------------- 95 | | 96 | | The following language lines are used to swap attribute place-holders 97 | | with something more reader friendly such as "E-Mail Address" instead 98 | | of "email". Your users will thank you. 99 | | 100 | | The Validator class will automatically search this array of lines it 101 | | is attempting to replace the :attribute place-holder in messages. 102 | | It's pretty slick. We think you'll like it. 103 | | 104 | */ 105 | 106 | 'attributes' => array(), 107 | 108 | ); -------------------------------------------------------------------------------- /extending_laravels_validation_class/application/libraries/validator.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /getting_started_with_amazon_product_api/amazon_product_api_class.php: -------------------------------------------------------------------------------- 1 | public_key = $public; 81 | $this->private_key = $private; 82 | $this->local_site = $local_site; 83 | $this->associate_tag = $associate_tag; 84 | 85 | } 86 | 87 | public function get_local(){ 88 | return $this->local_site; 89 | } 90 | 91 | /** 92 | * Check if the xml received from Amazon is valid 93 | * 94 | * @param mixed $response xml response to check 95 | * @return bool false if the xml is invalid 96 | * @return mixed the xml response if it is valid 97 | * @return exception if we could not connect to Amazon 98 | */ 99 | private function verifyXmlResponse($response) 100 | { 101 | if ($response === False) 102 | { 103 | throw new Exception("Could not connect to Amazon"); 104 | } 105 | else 106 | { 107 | if (isset($response->Items->Item->ItemAttributes->Title)) 108 | { 109 | return ($response); 110 | } 111 | else 112 | { 113 | throw new Exception("Invalid xml response."); 114 | } 115 | } 116 | } 117 | 118 | 119 | /** 120 | * Query Amazon with the issued parameters 121 | * 122 | * @param array $parameters parameters to query around 123 | * @return simpleXmlObject xml query response 124 | */ 125 | public function queryAmazon($parameters) 126 | { 127 | return amazon_product_api_signed_request($this->local_site, $parameters, $this->public_key, $this->private_key, $this->associate_tag); 128 | } 129 | 130 | 131 | /** 132 | * Return details of products searched by various types 133 | * 134 | * @param string $search search term 135 | * @param string $category search category 136 | * @param string $searchType type of search 137 | * @return mixed simpleXML object 138 | */ 139 | public function searchProducts($search, $category, $searchType = "UPC") 140 | { 141 | $allowedTypes = array("UPC", "TITLE", "ARTIST", "KEYWORD"); 142 | $allowedCategories = array("Music", "DVD", "VideoGames"); 143 | 144 | switch($searchType) 145 | { 146 | case "UPC" : $parameters = array("Operation" => "ItemLookup", 147 | "ItemId" => $search, 148 | "SearchIndex" => $category, 149 | "IdType" => "UPC", 150 | "ResponseGroup" => "Medium"); 151 | break; 152 | 153 | case "TITLE" : $parameters = array("Operation" => "ItemSearch", 154 | "Title" => $search, 155 | "SearchIndex" => $category, 156 | "ResponseGroup" => "Medium"); 157 | break; 158 | 159 | } 160 | 161 | $xml_response = $this->queryAmazon($parameters); 162 | 163 | return $this->verifyXmlResponse($xml_response); 164 | 165 | } 166 | 167 | 168 | 169 | 170 | public function getBrowseNodeProducts($category, $browseNode = 1000, $searchType = "UPC") 171 | { 172 | $allowedTypes = array("UPC", "TITLE", "ARTIST", "KEYWORD"); 173 | $allowedCategories = array("Music", "DVD", "VideoGames"); 174 | 175 | $parameters = array( 176 | "Operation" => "ItemSearch", 177 | "BrowseNode" => $browseNode, 178 | "SearchIndex" => $category, 179 | "ResponseGroup" => "Medium,Reviews" 180 | ); 181 | 182 | $xml_response = $this->queryAmazon($parameters); 183 | 184 | return $this->verifyXmlResponse($xml_response); 185 | 186 | } 187 | 188 | 189 | /** 190 | * Return details of a product searched by UPC 191 | * 192 | * @param int $upc_code UPC code of the product to search 193 | * @param string $product_type type of the product 194 | * @return mixed simpleXML object 195 | */ 196 | public function getItemByUpc($upc_code, $product_type) 197 | { 198 | $parameters = array("Operation" => "ItemLookup", 199 | "ItemId" => $upc_code, 200 | "SearchIndex" => $product_type, 201 | "IdType" => "UPC", 202 | "ResponseGroup" => "Medium"); 203 | 204 | $xml_response = $this->queryAmazon($parameters); 205 | 206 | return $this->verifyXmlResponse($xml_response); 207 | 208 | } 209 | 210 | 211 | /** 212 | * Return details of a product searched by ASIN 213 | * 214 | * @param int $asin_code ASIN code of the product to search 215 | * @return mixed simpleXML object 216 | */ 217 | public function getItemByAsin($asin_code) 218 | { 219 | $parameters = array("Operation" => "ItemLookup", 220 | "ItemId" => $asin_code, 221 | "ResponseGroup" => "Medium"); 222 | 223 | $xml_response = $this->queryAmazon($parameters); 224 | 225 | return $this->verifyXmlResponse($xml_response); 226 | } 227 | 228 | 229 | /** 230 | * Return details of a product searched by keyword 231 | * 232 | * @param string $keyword keyword to search 233 | * @param string $product_type type of the product 234 | * @return mixed simpleXML object 235 | */ 236 | public function getItemByKeyword($keyword, $product_type) 237 | { 238 | $parameters = array("Operation" => "ItemSearch", 239 | "Keywords" => $keyword, 240 | "SearchIndex" => $product_type); 241 | 242 | $xml_response = $this->queryAmazon($parameters); 243 | 244 | return $this->verifyXmlResponse($xml_response); 245 | } 246 | 247 | } 248 | 249 | ?> 250 | -------------------------------------------------------------------------------- /getting_started_with_amazon_product_api/amazon_product_api_signed_request.php: -------------------------------------------------------------------------------- 1 | $value) 65 | { 66 | $param = str_replace("%7E", "~", rawurlencode($param)); 67 | $value = str_replace("%7E", "~", rawurlencode($value)); 68 | $canonicalized_query[] = $param."=".$value; 69 | } 70 | 71 | $canonicalized_query = implode("&", $canonicalized_query); 72 | 73 | $string_to_sign = $method."\n".$host."\n".$uri."\n".$canonicalized_query; 74 | 75 | /* calculate the signature using HMAC with SHA256 and base64-encoding. 76 | The 'hash_hmac' function is only available from PHP 5 >= 5.1.2. 77 | */ 78 | $signature = base64_encode(hash_hmac("sha256", $string_to_sign, $private_key, True)); 79 | 80 | /* encode the signature for the request */ 81 | $signature = str_replace("%7E", "~", rawurlencode($signature)); 82 | 83 | /* create request */ 84 | $request = "http://".$host.$uri."?".$canonicalized_query."&Signature=".$signature; 85 | 86 | /* I prefer using CURL */ 87 | $ch = curl_init(); 88 | curl_setopt($ch, CURLOPT_URL,$request); 89 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 90 | curl_setopt($ch, CURLOPT_TIMEOUT, 15); 91 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); 92 | 93 | $xml_response = curl_exec($ch); 94 | 95 | /* If cURL doesn't work for you, then use the 'file_get_contents' 96 | function as given below. 97 | */ 98 | 99 | if ($xml_response === False) 100 | { 101 | return False; 102 | } 103 | else 104 | { 105 | /* parse XML */ 106 | $parsed_xml = @simplexml_load_string($xml_response); 107 | return ($parsed_xml === False) ? False : $parsed_xml; 108 | } 109 | } 110 | ?> 111 | -------------------------------------------------------------------------------- /getting_started_with_amazon_product_api/index.php: -------------------------------------------------------------------------------- 1 | 'SimilarityLookup', 12 | 'ItemId' => 'B0006N149M', 13 | 'Condition' => 'All', 14 | 'ResponseGroup' => 'Medium' 15 | ); 16 | 17 | $result = $amazon->queryAmazon($similar); 18 | $similar_products = $result->Items->Item; 19 | 20 | foreach($similar_products as $si){ 21 | 22 | $item_url = $si->DetailPageURL; //get its amazon url 23 | $img = $si->MediumImage->URL; //get the image url 24 | 25 | echo "
  • "; 26 | echo ""; 27 | echo "". $si->ASIN . ""; 28 | echo $si->ItemAttributes->ListPrice->FormattedPrice; //item price 29 | echo "
  • "; 30 | } 31 | ?> -------------------------------------------------------------------------------- /getting_started_with_freebase_api/class.freebase.php: -------------------------------------------------------------------------------- 1 | api_key; 17 | 18 | 19 | return json_decode(file_get_contents($url), true)['result']; 20 | } 21 | 22 | public function image($entity_id, $max_width = 150, $max_height = 150){ 23 | 24 | $url = 'https://usercontent.googleapis.com/freebase/v1/image' . $entity_id; 25 | $url .= '?maxwidth=' . $max_width; 26 | $url .= '&maxheight=' . $max_height; 27 | $url .= '&key=' . $this->api_key; 28 | 29 | return $url; 30 | } 31 | 32 | public function text($entity_id, $max_length = '0'){ 33 | 34 | $url = 'https://www.googleapis.com/freebase/v1/text/' . $entity_id; 35 | $url .= '?maxlength=' . $max_length; 36 | $url .= '&lang=fr'; 37 | $url .= '&key=' . $this->api_key; 38 | 39 | 40 | return json_decode(file_get_contents($url), true)['result']; 41 | } 42 | 43 | public function topic($entity_id){ 44 | 45 | $url = 'https://www.googleapis.com/freebase/v1/topic' . $entity_id; 46 | return json_decode(file_get_contents($url), true); 47 | } 48 | } 49 | ?> 50 | -------------------------------------------------------------------------------- /getting_started_with_freebase_api/test.freebase.php: -------------------------------------------------------------------------------- 1 | search('Dragon ball z', 'all type:manga'); 6 | 7 | foreach($result as $entity){ 8 | 9 | $id = $entity['mid']; 10 | $name = $entity['name']; 11 | 12 | $image = $freebase->image($id); 13 | $text = $freebase->text($id); 14 | ?> 15 |
  • 16 |

    17 | <?php echo $name; ?> 18 |

    19 | 20 |

    21 |
  • 22 | -------------------------------------------------------------------------------- /gmaps/index.php: -------------------------------------------------------------------------------- 1 | query("SELECT * FROM tbl_places"); 4 | ?> 5 | 18 |
    19 |
    20 |
    21 | 22 |

    23 | 24 | 25 |

    26 | 27 |

    28 | 29 | 30 |

    31 | 32 | 33 | 34 |

    35 | 36 | 37 |

    38 | 39 |

    40 | 41 | 42 |

    43 | 44 |

    45 | 46 | 47 |

    48 | 49 | 50 | 51 | fetch_object()){ ?> 52 | 53 | 54 | 55 | 56 | 57 | 58 | 61 | -------------------------------------------------------------------------------- /gmaps/places_config.php: -------------------------------------------------------------------------------- 1 | connect_errno){ 4 | die('Connect Error: ' . $db->connect_errno); 5 | } 6 | ?> -------------------------------------------------------------------------------- /gmaps/save_place.php: -------------------------------------------------------------------------------- 1 | query("INSERT INTO tbl_places SET place='$place', description='$description', lat='$latitude', lng='$longitude'"); 8 | $place_id = $db->insert_id; 9 | echo $place_id; 10 | ?> -------------------------------------------------------------------------------- /gmaps/sql/db.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `tbl_places` ( 2 | `place_id` int(10) NOT NULL AUTO_INCREMENT, 3 | `place` varchar(160) NOT NULL, 4 | `description` varchar(200) NOT NULL, 5 | `lat` float(15,11) NOT NULL, 6 | `lng` float(15,11) NOT NULL, 7 | PRIMARY KEY (`place_id`) 8 | ) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=latin1; 9 | -------------------------------------------------------------------------------- /mustache/data.php: -------------------------------------------------------------------------------- 1 | false, 'magic_word'=>'cool', 'name'=>'naruto', 'skills'=>array('rasenshuriken'=>array('super', 'golden', 'tsukasenmai'), 'rasengan'=>array('abc','def','ghi'), 'kage bunshin'=>array('kame', 'hame', 'wave'))); 3 | echo json_encode($ninja); -------------------------------------------------------------------------------- /mustache/data2.php: -------------------------------------------------------------------------------- 1 | [ 3 | 'naruto'=>['name'=>'naruto', 'skills'=>['rasengan', 'kage bunshin']], 4 | 'sasuke'=>['name'=>'sasuke', 'skills'=>['chidori', 'sharingan']], 5 | 'lee'=>['name'=>'lee', 'skills'=>['leaf hurricane', '5 gates']] 6 | ] 7 | ]; 8 | 9 | echo json_encode($data2); -------------------------------------------------------------------------------- /mustache/mustache.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * mustache.js - Logic-less {{mustache}} templates with JavaScript 3 | * http://github.com/janl/mustache.js 4 | */ 5 | var Mustache = (typeof module !== "undefined" && module.exports) || {}; 6 | 7 | (function (exports) { 8 | 9 | exports.name = "mustache.js"; 10 | exports.version = "0.5.1-dev"; 11 | exports.tags = ["{{", "}}"]; 12 | 13 | exports.parse = parse; 14 | exports.clearCache = clearCache; 15 | exports.compile = compile; 16 | exports.compilePartial = compilePartial; 17 | exports.render = render; 18 | 19 | exports.Scanner = Scanner; 20 | exports.Context = Context; 21 | exports.Renderer = Renderer; 22 | 23 | // This is here for backwards compatibility with 0.4.x. 24 | exports.to_html = function (template, view, partials, send) { 25 | var result = render(template, view, partials); 26 | 27 | if (typeof send === "function") { 28 | send(result); 29 | } else { 30 | return result; 31 | } 32 | }; 33 | 34 | var whiteRe = /\s*/; 35 | var spaceRe = /\s+/; 36 | var nonSpaceRe = /\S/; 37 | var eqRe = /\s*=/; 38 | var curlyRe = /\s*\}/; 39 | var tagRe = /#|\^|\/|>|\{|&|=|!/; 40 | 41 | // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577 42 | // See https://github.com/janl/mustache.js/issues/189 43 | function testRe(re, string) { 44 | return RegExp.prototype.test.call(re, string); 45 | } 46 | 47 | function isWhitespace(string) { 48 | return !testRe(nonSpaceRe, string); 49 | } 50 | 51 | var isArray = Array.isArray || function (obj) { 52 | return Object.prototype.toString.call(obj) === "[object Array]"; 53 | }; 54 | 55 | // OSWASP Guidlines: escape all non alphanumeric characters in ASCII space. 56 | var jsCharsRe = /[\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\xFF\u2028\u2029]/gm; 57 | 58 | function quote(text) { 59 | var escaped = text.replace(jsCharsRe, function (c) { 60 | return "\\u" + ('0000' + c.charCodeAt(0).toString(16)).slice(-4); 61 | }); 62 | 63 | return '"' + escaped + '"'; 64 | } 65 | 66 | function escapeRe(string) { 67 | return string.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 68 | } 69 | 70 | var entityMap = { 71 | "&": "&", 72 | "<": "<", 73 | ">": ">", 74 | '"': '"', 75 | "'": ''', 76 | "/": '/' 77 | }; 78 | 79 | function escapeHtml(string) { 80 | return String(string).replace(/[&<>"'\/]/g, function (s) { 81 | return entityMap[s]; 82 | }); 83 | } 84 | 85 | // Export these utility functions. 86 | exports.isWhitespace = isWhitespace; 87 | exports.isArray = isArray; 88 | exports.quote = quote; 89 | exports.escapeRe = escapeRe; 90 | exports.escapeHtml = escapeHtml; 91 | 92 | function Scanner(string) { 93 | this.string = string; 94 | this.tail = string; 95 | this.pos = 0; 96 | } 97 | 98 | /** 99 | * Returns `true` if the tail is empty (end of string). 100 | */ 101 | Scanner.prototype.eos = function () { 102 | return this.tail === ""; 103 | }; 104 | 105 | /** 106 | * Tries to match the given regular expression at the current position. 107 | * Returns the matched text if it can match, `null` otherwise. 108 | */ 109 | Scanner.prototype.scan = function (re) { 110 | var match = this.tail.match(re); 111 | 112 | if (match && match.index === 0) { 113 | this.tail = this.tail.substring(match[0].length); 114 | this.pos += match[0].length; 115 | return match[0]; 116 | } 117 | 118 | return null; 119 | }; 120 | 121 | /** 122 | * Skips all text until the given regular expression can be matched. Returns 123 | * the skipped string, which is the entire tail of this scanner if no match 124 | * can be made. 125 | */ 126 | Scanner.prototype.scanUntil = function (re) { 127 | var match, pos = this.tail.search(re); 128 | 129 | switch (pos) { 130 | case -1: 131 | match = this.tail; 132 | this.pos += this.tail.length; 133 | this.tail = ""; 134 | break; 135 | case 0: 136 | match = null; 137 | break; 138 | default: 139 | match = this.tail.substring(0, pos); 140 | this.tail = this.tail.substring(pos); 141 | this.pos += pos; 142 | } 143 | 144 | return match; 145 | }; 146 | 147 | function Context(view, parent) { 148 | this.view = view; 149 | this.parent = parent; 150 | this.clearCache(); 151 | } 152 | 153 | Context.make = function (view) { 154 | return (view instanceof Context) ? view : new Context(view); 155 | }; 156 | 157 | Context.prototype.clearCache = function () { 158 | this._cache = {}; 159 | }; 160 | 161 | Context.prototype.push = function (view) { 162 | return new Context(view, this); 163 | }; 164 | 165 | Context.prototype.lookup = function (name) { 166 | var value = this._cache[name]; 167 | 168 | if (!value) { 169 | if (name === ".") { 170 | value = this.view; 171 | } else { 172 | var context = this; 173 | 174 | while (context) { 175 | if (name.indexOf(".") > 0) { 176 | var names = name.split("."), i = 0; 177 | 178 | value = context.view; 179 | 180 | while (value && i < names.length) { 181 | value = value[names[i++]]; 182 | } 183 | } else { 184 | value = context.view[name]; 185 | } 186 | 187 | if (value != null) { 188 | break; 189 | } 190 | 191 | context = context.parent; 192 | } 193 | } 194 | 195 | this._cache[name] = value; 196 | } 197 | 198 | if (typeof value === "function") { 199 | value = value.call(this.view); 200 | } 201 | 202 | return value; 203 | }; 204 | 205 | function Renderer() { 206 | this.clearCache(); 207 | } 208 | 209 | Renderer.prototype.clearCache = function () { 210 | this._cache = {}; 211 | this._partialCache = {}; 212 | }; 213 | 214 | Renderer.prototype.compile = function (tokens, tags) { 215 | var fn = compileTokens(tokens), 216 | self = this; 217 | 218 | return function (view) { 219 | return fn(Context.make(view), self); 220 | }; 221 | }; 222 | 223 | Renderer.prototype.compilePartial = function (name, tokens, tags) { 224 | this._partialCache[name] = this.compile(tokens, tags); 225 | return this._partialCache[name]; 226 | }; 227 | 228 | Renderer.prototype.render = function (template, view) { 229 | var fn = this._cache[template]; 230 | 231 | if (!fn) { 232 | fn = this.compile(template); 233 | this._cache[template] = fn; 234 | } 235 | 236 | return fn(view); 237 | }; 238 | 239 | Renderer.prototype._section = function (name, context, callback) { 240 | var value = context.lookup(name); 241 | 242 | switch (typeof value) { 243 | case "object": 244 | if (isArray(value)) { 245 | var buffer = ""; 246 | for (var i = 0, len = value.length; i < len; ++i) { 247 | buffer += callback(context.push(value[i]), this); 248 | } 249 | return buffer; 250 | } else { 251 | return callback(context.push(value), this); 252 | } 253 | break; 254 | case "function": 255 | var sectionText = callback(context, this), self = this; 256 | var scopedRender = function (template) { 257 | return self.render(template, context); 258 | }; 259 | return value.call(context.view, sectionText, scopedRender) || ""; 260 | break; 261 | default: 262 | if (value) { 263 | return callback(context, this); 264 | } 265 | } 266 | 267 | return ""; 268 | }; 269 | 270 | Renderer.prototype._inverted = function (name, context, callback) { 271 | var value = context.lookup(name); 272 | 273 | // From the spec: inverted sections may render text once based on the 274 | // inverse value of the key. That is, they will be rendered if the key 275 | // doesn't exist, is false, or is an empty list. 276 | if (value == null || value === false || (isArray(value) && value.length === 0)) { 277 | return callback(context, this); 278 | } 279 | 280 | return ""; 281 | }; 282 | 283 | Renderer.prototype._partial = function (name, context) { 284 | var fn = this._partialCache[name]; 285 | 286 | if (fn) { 287 | return fn(context, this); 288 | } 289 | 290 | return ""; 291 | }; 292 | 293 | Renderer.prototype._name = function (name, context, escape) { 294 | var value = context.lookup(name); 295 | 296 | if (typeof value === "function") { 297 | value = value.call(context.view); 298 | } 299 | 300 | var string = (value == null) ? "" : String(value); 301 | 302 | if (escape) { 303 | return escapeHtml(string); 304 | } 305 | 306 | return string; 307 | }; 308 | 309 | /** 310 | * Low-level function that compiles the given `tokens` into a 311 | * function that accepts two arguments: a Context and a 312 | * Renderer. Returns the body of the function as a string if 313 | * `returnBody` is true. 314 | */ 315 | function compileTokens(tokens, returnBody) { 316 | if (typeof tokens === "string") { 317 | tokens = parse(tokens); 318 | } 319 | 320 | var body = ['""']; 321 | var token, method, escape; 322 | 323 | for (var i = 0, len = tokens.length; i < len; ++i) { 324 | token = tokens[i]; 325 | 326 | switch (token.type) { 327 | case "#": 328 | case "^": 329 | method = (token.type === "#") ? "_section" : "_inverted"; 330 | body.push("r." + method + "(" + quote(token.value) + ", c, function (c, r) {\n" + 331 | " " + compileTokens(token.tokens, true) + "\n" + 332 | "})"); 333 | break; 334 | case "{": 335 | case "&": 336 | case "name": 337 | escape = token.type === "name" ? "true" : "false"; 338 | body.push("r._name(" + quote(token.value) + ", c, " + escape + ")"); 339 | break; 340 | case ">": 341 | body.push("r._partial(" + quote(token.value) + ", c)"); 342 | break; 343 | case "text": 344 | body.push(quote(token.value)); 345 | break; 346 | } 347 | } 348 | 349 | // Convert to a string body. 350 | body = "return " + body.join(" + ") + ";"; 351 | 352 | // Good for debugging. 353 | // console.log(body); 354 | 355 | if (returnBody) { 356 | return body; 357 | } 358 | 359 | // For great evil! 360 | return new Function("c, r", body); 361 | } 362 | 363 | function escapeTags(tags) { 364 | if (tags.length === 2) { 365 | return [ 366 | new RegExp(escapeRe(tags[0]) + "\\s*"), 367 | new RegExp("\\s*" + escapeRe(tags[1])) 368 | ]; 369 | } 370 | 371 | throw new Error("Invalid tags: " + tags.join(" ")); 372 | } 373 | 374 | /** 375 | * Forms the given linear array of `tokens` into a nested tree structure 376 | * where tokens that represent a section have a "tokens" array property 377 | * that contains all tokens that are in that section. 378 | */ 379 | function nestTokens(tokens) { 380 | var tree = []; 381 | var collector = tree; 382 | var sections = []; 383 | var token, section; 384 | 385 | for (var i = 0; i < tokens.length; ++i) { 386 | token = tokens[i]; 387 | 388 | switch (token.type) { 389 | case "#": 390 | case "^": 391 | token.tokens = []; 392 | sections.push(token); 393 | collector.push(token); 394 | collector = token.tokens; 395 | break; 396 | case "/": 397 | if (sections.length === 0) { 398 | throw new Error("Unopened section: " + token.value); 399 | } 400 | 401 | section = sections.pop(); 402 | 403 | if (section.value !== token.value) { 404 | throw new Error("Unclosed section: " + section.value); 405 | } 406 | 407 | if (sections.length > 0) { 408 | collector = sections[sections.length - 1].tokens; 409 | } else { 410 | collector = tree; 411 | } 412 | break; 413 | default: 414 | collector.push(token); 415 | } 416 | } 417 | 418 | // Make sure there were no open sections when we're done. 419 | section = sections.pop(); 420 | 421 | if (section) { 422 | throw new Error("Unclosed section: " + section.value); 423 | } 424 | 425 | return tree; 426 | } 427 | 428 | /** 429 | * Combines the values of consecutive text tokens in the given `tokens` array 430 | * to a single token. 431 | */ 432 | function squashTokens(tokens) { 433 | var lastToken; 434 | 435 | for (var i = 0; i < tokens.length; ++i) { 436 | var token = tokens[i]; 437 | 438 | if (lastToken && lastToken.type === "text" && token.type === "text") { 439 | lastToken.value += token.value; 440 | tokens.splice(i--, 1); // Remove this token from the array. 441 | } else { 442 | lastToken = token; 443 | } 444 | } 445 | } 446 | 447 | /** 448 | * Breaks up the given `template` string into a tree of token objects. If 449 | * `tags` is given here it must be an array with two string values: the 450 | * opening and closing tags used in the template (e.g. ["<%", "%>"]). Of 451 | * course, the default is to use mustaches (i.e. Mustache.tags). 452 | */ 453 | function parse(template, tags) { 454 | tags = tags || exports.tags; 455 | var tagRes = escapeTags(tags); 456 | 457 | var scanner = new Scanner(template); 458 | 459 | var tokens = [], // Buffer to hold the tokens 460 | spaces = [], // Indices of whitespace tokens on the current line 461 | hasTag = false, // Is there a {{tag}} on the current line? 462 | nonSpace = false; // Is there a non-space char on the current line? 463 | 464 | // Strips all whitespace tokens array for the current line 465 | // if there was a {{#tag}} on it and otherwise only space. 466 | var stripSpace = function () { 467 | if (hasTag && !nonSpace) { 468 | while (spaces.length) { 469 | tokens.splice(spaces.pop(), 1); 470 | } 471 | } else { 472 | spaces = []; 473 | } 474 | 475 | hasTag = false; 476 | nonSpace = false; 477 | }; 478 | 479 | var type, value, chr; 480 | 481 | while (!scanner.eos()) { 482 | value = scanner.scanUntil(tagRes[0]); 483 | 484 | if (value) { 485 | for (var i = 0, len = value.length; i < len; ++i) { 486 | chr = value[i]; 487 | 488 | if (isWhitespace(chr)) { 489 | spaces.push(tokens.length); 490 | } else { 491 | nonSpace = true; 492 | } 493 | 494 | tokens.push({type: "text", value: chr}); 495 | 496 | if (chr === "\n") { 497 | stripSpace(); // Check for whitespace on the current line. 498 | } 499 | } 500 | } 501 | 502 | // Match the opening tag. 503 | if (!scanner.scan(tagRes[0])) { 504 | break; 505 | } 506 | 507 | hasTag = true; 508 | type = scanner.scan(tagRe) || "name"; 509 | 510 | // Skip any whitespace between tag and value. 511 | scanner.scan(whiteRe); 512 | 513 | // Extract the tag value. 514 | if (type === "=") { 515 | value = scanner.scanUntil(eqRe); 516 | scanner.scan(eqRe); 517 | scanner.scanUntil(tagRes[1]); 518 | } else if (type === "{") { 519 | var closeRe = new RegExp("\\s*" + escapeRe("}" + tags[1])); 520 | value = scanner.scanUntil(closeRe); 521 | scanner.scan(curlyRe); 522 | scanner.scanUntil(tagRes[1]); 523 | } else { 524 | value = scanner.scanUntil(tagRes[1]); 525 | } 526 | 527 | // Match the closing tag. 528 | if (!scanner.scan(tagRes[1])) { 529 | throw new Error("Unclosed tag at " + scanner.pos); 530 | } 531 | 532 | tokens.push({type: type, value: value}); 533 | 534 | if (type === "name" || type === "{" || type === "&") { 535 | nonSpace = true; 536 | } 537 | 538 | // Set the tags for the next time around. 539 | if (type === "=") { 540 | tags = value.split(spaceRe); 541 | tagRes = escapeTags(tags); 542 | } 543 | } 544 | 545 | squashTokens(tokens); 546 | 547 | return nestTokens(tokens); 548 | } 549 | 550 | // The high-level clearCache, compile, compilePartial, and render functions 551 | // use this default renderer. 552 | var _renderer = new Renderer; 553 | 554 | /** 555 | * Clears all cached templates and partials. 556 | */ 557 | function clearCache() { 558 | _renderer.clearCache(); 559 | } 560 | 561 | /** 562 | * High-level API for compiling the given `tokens` down to a reusable 563 | * function. If `tokens` is a string it will be parsed using the given `tags` 564 | * before it is compiled. 565 | */ 566 | function compile(tokens, tags) { 567 | return _renderer.compile(tokens, tags); 568 | } 569 | 570 | /** 571 | * High-level API for compiling the `tokens` for the partial with the given 572 | * `name` down to a reusable function. If `tokens` is a string it will be 573 | * parsed using the given `tags` before it is compiled. 574 | */ 575 | function compilePartial(name, tokens, tags) { 576 | return _renderer.compilePartial(name, tokens, tags); 577 | } 578 | 579 | /** 580 | * High-level API for rendering the `template` using the given `view`. The 581 | * optional `partials` object may be given here for convenience, but note that 582 | * it will cause all partials to be re-compiled, thus hurting performance. Of 583 | * course, this only matters if you're going to render the same template more 584 | * than once. If so, it is best to call `compilePartial` before calling this 585 | * function and to leave the `partials` argument blank. 586 | */ 587 | function render(template, view, partials) { 588 | if (partials) { 589 | for (var name in partials) { 590 | compilePartial(name, partials[name]); 591 | } 592 | } 593 | 594 | return _renderer.render(template, view); 595 | } 596 | 597 | })(Mustache); -------------------------------------------------------------------------------- /mustache/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 114 |
    115 |
    116 | First Timer: 117 |
    118 |
    119 | Remembering: 120 |
    121 |
    122 | Experimenting/ Playing: 123 |
    124 |
    125 |
    126 | Diving: 127 |
    128 |
    129 |
    130 | Using HTML: 131 |
    132 |
    133 | 134 |
    135 | 155 | 156 | 170 | 171 | 186 | 187 | 196 |
    197 | No templates:
    198 |
    199 |
    200 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Tutorials 2 | 3 | A collection of code examples from the articles that I have used in my [blog](http://wernancheta.com). 4 | 5 | 6 | ## Donation 7 | 8 | If this project helped you reduce time to develop, please consider buying me a cup of coffee :) 9 | 10 | Buy Me A Coffee 11 | -------------------------------------------------------------------------------- /registration_system_using_knockoutjs/refresher.css: -------------------------------------------------------------------------------- 1 | .new_student { 2 | margin-bottom: 20px; 3 | } 4 | 5 | td, th { 6 | padding: 10px; 7 | } 8 | 9 | .container { 10 | padding: 16px; 11 | } 12 | 13 | thead { 14 | background-color: #ccc; 15 | } 16 | 17 | td { 18 | background-color: #dee; 19 | } 20 | 21 | .age { 22 | width: 37px; 23 | } 24 | 25 | .name { 26 | width: 218px; 27 | } -------------------------------------------------------------------------------- /registration_system_using_knockoutjs/refresher.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
    6 |
    7 | 8 | 9 | 10 | 11 |
    12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 32 | 33 | 34 | 35 | 36 |
    NameAgeRemoveUpdate
    25 | 26 | 27 | 29 | 30 | 31 | removeupdate
    37 | 38 | 39 |
    40 | 41 | 42 | 43 | 44 | 161 | -------------------------------------------------------------------------------- /registration_system_using_knockoutjs/refresher_save.php: -------------------------------------------------------------------------------- 1 | query("INSERT INTO students SET name = '$name', age = '$age'"); 18 | echo $db->insert_id; //last insert id 19 | break; 20 | 21 | case 'update': 22 | 23 | $id = $student['id']; 24 | $db->query("UPDATE students SET name = '$name', age = '$age' WHERE id = '$id'"); 25 | break; 26 | 27 | case 'delete': 28 | 29 | $id = $_POST['student_id']; 30 | $db->query("UPDATE students SET status = 0 WHERE id = '$id'"); 31 | break; 32 | 33 | default: 34 | $students = $db->query("SELECT * FROM students WHERE status = 1"); 35 | $students_r = array(); 36 | while($row = $students->fetch_array()){ 37 | 38 | $id = $row['id']; 39 | $name = $row['name']; 40 | $age = $row['age']; 41 | $name_update = false; 42 | $age_update = false; 43 | $name_focus = false; 44 | $age_focus = false; 45 | 46 | $students_r[] = array( 47 | 'id' => $id, 'name' => $name, 'age' => $age, 48 | 'nameUpdate' => $name_update, 'ageUpdate' => $age_update, 49 | 'nameHasFocus' => $name_focus, 'ageHasFocus' => $age_focus 50 | ); 51 | } 52 | 53 | echo json_encode($students_r); 54 | break; 55 | } 56 | ?> -------------------------------------------------------------------------------- /storejs/store.js: -------------------------------------------------------------------------------- 1 | // 2 | // store.js by Frank Kohlhepp 3 | // Copyright (c) 2011 - 2012 Frank Kohlhepp 4 | // https://github.com/frankkohlhepp/store-js 5 | // License: MIT-license 6 | // 7 | (function () { 8 | var has = function (object, key) { 9 | return Object.prototype.hasOwnProperty.call(object, key); 10 | }; 11 | 12 | var objectGetLength = function (object) { 13 | var count = 0; 14 | for (var key in object) { 15 | if (has(object, key)) { count++; } 16 | } 17 | 18 | return count; 19 | }; 20 | 21 | var arrayIndexOf = function (array, item, from) { 22 | var length = array.length >>> 0; 23 | for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) { 24 | if (array[i] === item) { return i; } 25 | } 26 | 27 | return -1; 28 | }; 29 | 30 | var arrayContains = function (array, item, from) { 31 | return arrayIndexOf(array, item, from) !== -1; 32 | }; 33 | 34 | var arrayInclude = function (array, item) { 35 | if (!arrayContains(array, item)) { array.push(item); } 36 | return array; 37 | }; 38 | 39 | var Store = this.Store = function (name, defaults, watcherSpeed) { 40 | this.name = name; 41 | this.defaults = defaults || {}; 42 | this.watcherSpeed = watcherSpeed || 500; 43 | this.listeners = {}; 44 | 45 | // Apply defaults 46 | this.applyDefaults(); 47 | }; 48 | 49 | Store.clear = function () { 50 | localStorage.clear(); 51 | }; 52 | 53 | Store.prototype.applyDefaults = function () { 54 | for (var key in this.defaults) { 55 | if (has(this.defaults, key) && this.get(key) === undefined) { 56 | this.set(key, this.defaults[key]); 57 | } 58 | } 59 | 60 | return this; 61 | }; 62 | 63 | Store.prototype.watcher = function (force) { 64 | if (this.watcherTimer) { 65 | clearTimeout(this.watcherTimer); 66 | } 67 | 68 | if (objectGetLength(this.listeners) || force) { 69 | this.newObject = this.toObject(); 70 | 71 | if (this.oldObject) { 72 | for (var key in this.newObject) { 73 | if (has(this.newObject, key) && this.newObject[key] !== this.oldObject[key]) { 74 | this.fireEvent(key, this.newObject[key]); 75 | } 76 | } 77 | 78 | for (var key in this.oldObject) { 79 | if (has(this.oldObject, key) && !has(this.newObject, key)) { 80 | this.fireEvent(key, this.newObject[key]); 81 | } 82 | } 83 | } 84 | 85 | this.oldObject = this.newObject; 86 | var that = this; 87 | this.watcherTimer = setTimeout(function () { 88 | that.watcher(); 89 | }, this.watcherSpeed); 90 | } 91 | 92 | return this; 93 | }; 94 | 95 | Store.prototype.get = function (name) { 96 | var value = localStorage.getItem("store." + this.name + "." + name); 97 | if (value === null) { return undefined; } 98 | try { return JSON.parse(value); } catch (e) { return null; } 99 | }; 100 | 101 | Store.prototype.set = function (name, value) { 102 | if (value === undefined) { 103 | this.remove(name); 104 | } else { 105 | if (typeof value === "function") { value = null; } 106 | try { value = JSON.stringify(value); } catch (e) { value = null; } 107 | localStorage.setItem("store." + this.name + "." + name, value); 108 | } 109 | 110 | return this; 111 | }; 112 | 113 | Store.prototype.remove = function (name) { 114 | localStorage.removeItem("store." + this.name + "." + name); 115 | return this.applyDefaults(); 116 | }; 117 | 118 | Store.prototype.reset = function () { 119 | var name = "store." + this.name + "."; 120 | for (var i = (localStorage.length - 1); i >= 0; i--) { 121 | if (localStorage.key(i).substring(0, name.length) === name) { 122 | localStorage.removeItem(localStorage.key(i)); 123 | } 124 | } 125 | 126 | return this.applyDefaults(); 127 | }; 128 | 129 | Store.prototype.toObject = function () { 130 | var values = {}; 131 | var name = "store." + this.name + "."; 132 | for (var i = (localStorage.length - 1); i >= 0; i--) { 133 | if (localStorage.key(i).substring(0, name.length) === name) { 134 | var key = localStorage.key(i).substring(name.length); 135 | var value = this.get(key); 136 | if (value !== undefined) { values[key] = value; } 137 | } 138 | } 139 | 140 | return values; 141 | }; 142 | 143 | Store.prototype.fromObject = function (values, merge) { 144 | if (!merge) { this.reset(); } 145 | for (var key in values) { 146 | if (has(values, key)) { 147 | this.set(key, values[key]); 148 | } 149 | } 150 | 151 | return this; 152 | }; 153 | 154 | Store.prototype.addEvent = function (selector, callback) { 155 | this.watcher(true); 156 | if (!this.listeners[selector]) { this.listeners[selector] = []; } 157 | arrayInclude(this.listeners[selector], callback); 158 | return this; 159 | }; 160 | 161 | Store.prototype.removeEvent = function (selector, callback) { 162 | for (var i = (this.listeners[selector].length - 1); i >= 0; i--) { 163 | if (this.listeners[selector][i] === callback) { this.listeners[selector].splice(i, 1); } 164 | } 165 | 166 | if (!this.listeners[selector].length) { delete this.listeners[selector]; } 167 | return this; 168 | }; 169 | 170 | Store.prototype.fireEvent = function (name, value) { 171 | var selectors = [name, "*"]; 172 | for (var i = 0; i < selectors.length; i++) { 173 | var selector = selectors[i]; 174 | if (this.listeners[selector]) { 175 | for (var j = 0; j < this.listeners[selector].length; j++) { 176 | this.listeners[selector][j](value, name, this.name); 177 | } 178 | } 179 | } 180 | 181 | return this; 182 | }; 183 | }()); -------------------------------------------------------------------------------- /storejs/teststore.html: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 |
    23 |

    Create Character

    24 |

    25 | 26 | 27 |

    28 | 29 |

    30 | 31 | 32 |

    33 | 34 |

    35 | 36 | 37 |

    38 | 39 |

    40 | 41 | 42 |

    43 |
    44 | 45 |
    46 | 47 | 133 | -------------------------------------------------------------------------------- /sugarjs/sugar.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Sugar Library v1.2.5 3 | * 4 | * Freely distributable and licensed under the MIT-style license. 5 | * Copyright (c) 2012 Andrew Plummer 6 | * http://sugarjs.com/ 7 | * 8 | * ---------------------------- */ 9 | (function(context){var i=true,j=null,l=false,n=Object,o=Array,p=RegExp,q=Date,r=String,s=Number,t=n.defineProperty&&n.defineProperties;function v(a,b,c,d){var e=b?a.prototype:a,f;w(a,b,d);x(d,function(g,h){f=e[g];if(typeof c==="function")h=aa(e[g],h,c);if(c!==l||!e[g])y(e,g,h);a.SugarMethods[g]={e:b,method:h,g:f}})} 10 | function w(a){if(!a.SugarMethods){y(a,"SugarMethods",{});v(a,l,l,{restore:function(){var b=arguments.length===0,c=z(arguments);x(a.SugarMethods,function(d,e){if(b||c.has(d))y(e.e?a.prototype:a,d,e.method)})},extend:function(b,c,d){a===n&&arguments.length===0?A(C.concat(D),Object):v(a,d!==l,c,b)}})}}function aa(a,b,c){return function(){return a&&(c===i||!c.apply(this,arguments))?a.apply(this,arguments):b.apply(this,arguments)}} 11 | function y(a,b,c){if(t)n.defineProperty(a,b,{value:c,configurable:i,enumerable:l,writable:i});else a[b]=c}function x(a,b){for(var c in a)n.prototype.hasOwnProperty.call(a,c)&&b.call(a,c,a[c])}function E(a,b,c,d){var e=i;if(a===b)return i;else if(n.isRegExp(b))return p(b).test(a);else if(n.isFunction(b))return b.apply(c,[a].concat(d));else if(n.isObject(b)&&n.isObject(a)){x(b,function(f){E(a[f],b[f],c,d)||(e=l)});return!n.isEmpty(b)&&e}else return n.equal(a,b)} 12 | function F(a,b){var c,d,e,f,g,h,k=typeof a;if(k==="string")return a;d=n.prototype.toString.call(a);c=d==="[object Object]";e=d==="[object Array]";if(a!=j&&c||e){b||(b=[]);if(b.length>1)for(g=b.length;g--;)if(b[g]===a)return"CYC";b.push(a);c=r(a.constructor);f=e?a:n.keys(a).sort();for(g=0;g0);return n.keys(a).length==0},equal:function(a,b){return F(a)===F(b)},values:function(a,b){var c=[];x(a,function(d,e){c.push(e);b&&b.call(a,e)});return c},clone:function(a,b){if(a==j||typeof a!=="object")return a;if(o.isArray(a))return a.clone();var c=a.constructor=== 18 | M?new M:{};return n.merge(c,a,b)},fromQueryString:function(a,b){var c=n.extended();a=a&&a.toString?a.toString():"";a.replace(/^.*?\?/,"").unescapeURL().split("&").each(function(d){d=d.split("=");d.length===2&&ca(c,d[0],d[1],b)});return c},tap:function(a,b){G(a,b,a,[a]);return a},has:function(a,b){return n.prototype.hasOwnProperty.call(a,b)}}); 19 | v(n,l,function(){return arguments.length>1},{keys:function(a,b){if(a==j||typeof a!="object"&&!n.isRegExp(a)&&!n.isFunction(a))throw new TypeError("Object required");var c=[];x(a,function(d,e){c.push(d);b&&b.call(a,d,e)});return c}});function K(a,b,c,d,e){var f,g;N(b);if(c<0)c=a.length+c;g=isNaN(c)?0:parseInt(c>>0);for(c=d===i?a.length+g:a.length;g>0);if(c<0)c=e+c;if(!f&&c<0||f&&c>=e)c=g;for(;f&&c>=0||!f&&c>>0==e&&e!=4294967295&&e>=c&&d.push(e.toNumber());d.sort().each(function(f){return b.call(a,a[f],f,a)});return a}function Q(a,b,c,d){var e=c==="max",f=c==="min",g=e?-Infinity:Infinity,h=[];x(a,function(k){var m=a[k];k=G(m,b,a,d?[m,k.toNumber(),a]:[]);if(k===g)h.push(m);else if(e&&k>g||f&&k0&&!n.isFunction(a[0])},{every:function(a,b){var c=this.length,d=0;for(P(arguments);d0?a.reduce(function(b,c){return b+c}):0},average:function(a){a=a?this.map(a):this;return a.length>0?a.sum()/a.length:0},groupBy:function(a,b){var c=this,d=n.extended(),e;K(c,function(f,g){e=G(f,a,c,[f,g,c]);d[e]||(d[e]=[]);d[e].push(f)});return d.each(b)},inGroups:function(a,b){var c= 32 | arguments.length>1,d=this,e=[],f=(this.length/a).ceil();(0).upto(a-1,function(g){g=g*f;var h=d.slice(g,g+f);c&&h.length0&&c.push(d);return c}, 33 | compact:function(a){var b=[];K(this,function(c){if(n.isArray(c))b.push(c.compact());else if(a&&c)b.push(c);else!a&&c!=j&&!n.isNaN(c)&&b.push(c)});return b},isEmpty:function(){return this.compact().length==0},flatten:function(a){return J(this,a)},sortBy:function(a,b){var c=this.clone();c.sort(function(d,e){var f,g;f=G(d,a,c,[d]);g=G(e,a,c,[e]);if(n.isString(f)&&n.isString(g)){f=f;g=g;var h,k,m,u,B=0,R=0;f=ia(f);g=ia(g);do{m=la(f,B);u=la(g,B);h=m?o.AlphanumericSortOrder.indexOf(m):j;k=u?o.AlphanumericSortOrder.indexOf(u): 34 | j;if(h===-1||k===-1){h=f.charCodeAt(B)||j;k=g.charCodeAt(B)||j}m=m!==f.charAt(B);u=u!==g.charAt(B);if(m!==u&&R===0)R=m-u;B+=1}while(h!=j&&k!=j&&h===k);f=h===k?R:hg?1:0;return f*(b?-1:1)});return c},randomize:function(){for(var a=this.concat(),b,c,d=a.length;d;b=parseInt(Math.random()*d),c=a[--d],a[d]=a[b],a[b]=c);return a},zip:function(){var a=I(arguments);return this.map(function(b,c){return[b].concat(a.map(function(d){return c in d?d[c]:j}))})},sample:function(a){var b=[], 35 | c=this.clone(),d;for(a>0||(a=1);b.length0?b:b[0]}});v(o,i,l,{all:o.prototype.every,any:o.prototype.some,has:o.prototype.some,insert:o.prototype.add});function S(a,b,c){c=Math[c||"round"];var d=Math.pow(10,(b||0).abs());if(b<0)d=1/d;return c(a*d)/d}function na(a,b,c,d){var e=[];a=parseInt(a);for(var f=d>0;f&&a<=b||!f&&a>=b;){e.push(a);c&&c.call(this,a);a+=d}return e} 36 | function T(a,b,c,d,e,f){var g=a.toFixed(20),h=g.search(/\./);g=g.search(/[1-9]/);h=h-g;if(h>0)h-=1;e=Math.max(Math.min((h/3).floor(),e===l?c.length:e),-d);d=c.charAt(e+d-1);if(h<-9){e=-3;b=h.abs()-9;d=c.first()}return(a/(f?(2).pow(10*e):(10).pow(e*3))).round(b||0).format()+d.trim()}v(s,l,l,{random:function(a,b){var c;if(arguments.length==1){b=a;a=0}c=Math.min(a||0,H(b)?1:b);return S(Math.random()*(Math.max(a||0,H(b)?1:b)-c)+c)}}); 37 | v(s,i,l,{toNumber:function(){return parseFloat(this,10)},abbr:function(a){return T(this,a,"kmbt",0,4)},metric:function(a,b){return T(this,a,"n\u03bcm kMGTPE",4,H(b)?1:b)},bytes:function(a,b){return T(this,a,"kMGTPE",0,H(b)?4:b,i)+"B"},isInteger:function(){return this%1==0},ceil:function(a){return S(this,a,"ceil")},floor:function(a){return S(this,a,"floor")},abs:function(){return Math.abs(this)},pow:function(a){if(H(a))a=1;return Math.pow(this,a)},round:function(a){return S(this,a,"round")},chr:function(){return r.fromCharCode(this)}, 38 | isOdd:function(){return!this.isMultipleOf(2)},isEven:function(){return this.isMultipleOf(2)},isMultipleOf:function(a){return this%a===0},upto:function(a,b,c){return na(this,a,b,c||1)},downto:function(a,b,c){return na(this,a,b,-(c||1))},times:function(a){if(a)for(var b=0;b=11&&b<=13)a="th";else switch(a%10){case 1:a="st";break;case 2:a="nd";break;case 3:a="rd";break; 39 | default:a="th"}return this.toString()+a},pad:function(a,b,c){c=c||10;c=this.toNumber()===0?"":this.toString(c).replace(/^-/,"");c=U(c,"0",a-c.replace(/\.\d+$/,"").length,0);if(b||this<0)c=(this<0?"-":"+")+c;return c},format:function(a,b,c){var d,e,f=/(\d+)(\d{3})/;if(r(b).match(/\d/))throw new TypeError("Thousands separator cannot contain numbers.");d=n.isNumber(a)?S(this,a).toFixed(Math.max(a,0)):this.toString();b=b||",";c=c||".";e=d.split(".");d=e[0];for(e=e[1]||"";d.match(f);)d=d.replace(f,"$1"+ 40 | b+"$2");if(e.length>0)d+=c+U(e,"0",0,a-e.length);return d},hex:function(a){return this.pad(a||1,l,16)}});function V(){return"\t\n\u000b\u000c\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u2028\u2029\u3000\ufeff"}function oa(a,b,c,d){var e=I(b).join("");e=e.replace(/all/,"").replace(/(\w)lphabet|umbers?|atakana|paces?|unctuation/g,"$1");return a.replace(c,function(f){return d[f]&&(!e||e.has(d[f].type))?d[f].to:f})} 41 | var pa=[{type:"a",shift:65248,start:65,end:90},{type:"a",shift:65248,start:97,end:122},{type:"n",shift:65248,start:48,end:57},{type:"p",shift:65248,start:33,end:47},{type:"p",shift:65248,start:58,end:64},{type:"p",shift:65248,start:91,end:96},{type:"p",shift:65248,start:123,end:126}],qa={},ra={},sa=/[\u0020-\u00A5]|[\uFF61-\uFF9F][\uff9e\uff9f]?/g,ta=/[\u3000-\u301C]|[\u301A-\u30FC]|[\uFF01-\uFF60]|[\uFFE0-\uFFE6]/g,ua=/[\u30ab\u30ad\u30af\u30b1\u30b3\u30b5\u30b7\u30b9\u30bb\u30bd\u30bf\u30c1\u30c4\u30c6\u30c8\u30cf\u30d2\u30d5\u30d8\u30db]/, 42 | va=/[\u30cf\u30d2\u30d5\u30d8\u30db\u30f2]/;function W(a,b,c){qa[b]={type:a,to:c};ra[c]={type:a,to:b}}function U(a,b,c,d){var e=String(b);if(e!=b)e="";n.isNumber(c)||(c=1);n.isNumber(d)||(d=1);return e.repeat(c)+a+e.repeat(d)}var X,Y; 43 | v(r,i,l,{escapeRegExp:function(){return p.escape(this)},escapeURL:function(a){return a?encodeURIComponent(this):encodeURI(this)},unescapeURL:function(a){return a?decodeURI(this):decodeURIComponent(this)},escapeHTML:function(){return this.replace(/&/g,"&").replace(//g,">")},unescapeHTML:function(){return this.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&")},encodeBase64:function(){return X(this)},decodeBase64:function(){return Y(this)},capitalize:function(a){return this.toLowerCase().replace(a? 44 | /^\S|\s\S/g:/^\S/,function(b){return b.toUpperCase()})},pad:function(a,b){return U(this,a,b,b)},padLeft:function(a,b){return U(this,a,b,0)},padRight:function(a,b){return U(this,a,0,b)},repeat:function(a){var b="",c=0;if(n.isNumber(a)&&a>0)for(;c0?"_":"")+a.toLowerCase()}).replace(/([A-Z\d]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").toLowerCase()},camelize:function(a){return this.underscore().replace(/(^|_)([^_]+)/g,function(b,c,d,e){b=r.Inflector&&r.Inflector.acronyms&&r.Inflector.acronyms[d];e=a!==l||e>0;if(b)return e?b:b.toLowerCase();return e?d.capitalize():d})},spacify:function(){return this.underscore().replace(/_/g," ")},stripTags:function(){var a= 50 | this;z(arguments.length>0?arguments:[""],function(b){a=a.replace(p("]*>","gi"),"")});return a},removeTags:function(){var a=this;z(arguments.length>0?arguments:["\\S+"],function(b){b=p("<("+b+")[^<>]*(?:\\/>|>.*?<\\/\\1>)","gi");a=a.replace(b,"")});return a},truncate:function(a,b,c,d){var e="",f="",g=this.toString(),h="["+V()+"]+",k="[^"+V()+"]*",m=p(h+k+"$");d=H(d)?"...":r(d);if(g.length<=a)return g;switch(c){case "left":a=g.length-a;e=d;g=g.slice(a);m=p("^"+k+h);break; 51 | case "middle":a=Math.floor(a/2);f=d+g.slice(g.length-a).trimLeft();g=g.slice(0,a);break;default:a=a;f=d;g=g.slice(0,a)}if(b===l&&this.slice(a,a+1).match(/\S/))g=g.remove(m);return e+g+f},assign:function(){var a=n.extended();z(arguments,function(b,c){if(n.isObject(b))a.merge(b);else a[c+1]=b});return this.replace(/\{(.+?)\}/g,function(b,c){return n.prototype.hasOwnProperty.call(a,c)?a[c]:b})}}); 52 | v(r,i,function(a){return n.isRegExp(a)},{split:function(a,b){var c=[],d=0;a=p(a).addFlag("g");var e,f,g,h;p.c||(e=RegExp("^"+a.source+"$(?!\\s)",a.getFlags()));if(H(b)||b<0)b=Infinity;else{b|=0;if(!b)return[]}for(;f=a.exec(this);){g=f.index+f[0].length;if(g>d){c.push(this.slice(d,f.index));!p.c&&f.length>1&&f[0].replace(e,function(){for(var k=1;k1&&f.index= 53 | b)break}a.lastIndex===f.index&&a.lastIndex++}if(d===this.length){if(h||!a.test(""))c.push("")}else c.push(this.slice(d));return c.length>b?c.slice(0,b):c}});v(r,i,l,{insert:r.prototype.add});p.c=H(p("()??").exec("")[1]);function Z(a,b){var c="";if(b=="g"||a.global)c+="g";if(b=="i"||a.ignoreCase)c+="i";if(b=="m"||a.multiline)c+="m";if(b=="y"||a.h)c+="y";return c}v(p,l,l,{escape:function(a){n.isString(a)||(a=String(a));return a.replace(/([\\/'*+?|()\[\]{}.^$])/g,"\\$1")}}); 54 | v(p,i,l,{getFlags:function(){return Z(this)},setFlags:function(a){return p(this.source,a)},addFlag:function(a){return this.setFlags(Z(this,a))},removeFlag:function(a){return this.setFlags(Z(this).replace(a,""))}});function $(a,b,c,d,e){if(!a.b)a.b=[];n.isNumber(b)||(b=0);a.b.push(setTimeout(function(){a.b.removeAt(f);c.apply(d,e||[])},b));var f=a.b.length} 55 | v(Function,i,l,{lazy:function(a,b){function c(){if(!(f&&e.length>b-2)){e.push([this,arguments]);g()}}var d=this,e=[],f=l,g,h,k;a=a||1;b=b||Infinity;h=a.ceil();k=S(h/a);g=function(){if(!(f||e.length==0)){for(var m=Math.max(e.length-k,0);e.length>m;)Function.prototype.apply.apply(d,e.shift());$(c,h,function(){f=l;g()});f=i}};return c},delay:function(a){var b=I(arguments,1);$(this,a,this,this,b);return this},throttle:function(a){return this.lazy(a,1)},debounce:function(a){var b=this;return function(){b.cancel(); 56 | $(b,a,b,this,arguments)}},cancel:function(){if(n.isArray(this.b))for(;this.b.length>0;)clearTimeout(this.b.shift());return this},after:function(a){var b=this,c=0,d=[];if(n.isNumber(a)){if(a===0){b.call();return b}}else a=1;return function(){var e;d.push(Array.create(arguments));c++;if(c==a){e=b.call(this,d);c=0;d=[];return e}}},once:function(){var a=this;return function(){return n.prototype.hasOwnProperty.call(a,"memo")?a.memo:a.memo=a.apply(this,arguments)}},fill:function(){var a=this,b=I(arguments); 57 | return function(){var c=I(arguments);K(b,function(d,e){if(d!=j||e>=c.length)c.splice(e,0,d)});return a.apply(this,c)}}});(function(){var a={},b;K(["Array","Boolean","Date","Function","Number","String","RegExp"],function(c){b="is"+c;C.push(b);a[b]=function(d){return L(d,c)}});v(Object,l,l,a)})();A(D,M); 58 | (function(a){if(this.btoa){X=this.btoa;Y=this.atob}var b=/[^A-Za-z0-9\+\/\=]/g;X=function(c){var d="",e,f,g,h,k,m,u=0;do{e=c.charCodeAt(u++);f=c.charCodeAt(u++);g=c.charCodeAt(u++);h=e>>2;e=(e&3)<<4|f>>4;k=(f&15)<<2|g>>6;m=g&63;if(isNaN(f))k=m=64;else if(isNaN(g))m=64;d=d+a.charAt(h)+a.charAt(e)+a.charAt(k)+a.charAt(m)}while(u>4;f=(f&15)<<4|h>>2;g=(h&3)<<6|k;d+=e.chr();if(h!=64)d+=f.chr();if(k!=64)d+=g.chr()}while(m0)d.digits+=d.numbers.join(""); 88 | else d.numbers=x.split("");d.monthSuffix=e[1]}d.capitalizeUnit=a=="de";d.hasPlural=b(2);d.pastRelativeFormat=d.formats[0];d.futureRelativeFormat=d.formats[b(3)?1:0];d.durationFormat=d.formats[0].replace(/\s*\{sign\}\s*/,"");return d}function R(a){a||(a=Date.currentLocale);return a!="en"&&a!="en-US"}function Q(a){q.merge(this,a)} 89 | q.merge(Q.prototype,{getMonth:function(a){return q.isNumber(a)?a-1:this.months.findIndex(p(a,"i"))%12},l:function(a){return this.weekdays.findIndex(p(a,"i"))%7},k:function(a){var b;return q.isNumber(a)?a:a&&(b=this.numbers.indexOf(a))!==-1?(b+1)%10:1},o:function(a){var b=this;return a.replace(this.numbers[9],"").each(function(d){return b.k(d)}).join("")},n:function(a){return u.units[this.units.indexOf(a)%8]},r:function(a){return this.j(a,a[2]>0?"futureRelativeFormat":"pastRelativeFormat")},duration:function(a){return this.j(T(a), 90 | "durationFormat")},j:function(a,b){var d=a[0],e=a[1],g=a[2],f;if(this.code=="ru"){f=d.toString().from(-1);switch(j){case f==1:f=1;break;case f>=2&&f<=4:f=2;break;default:f=3}}else f=this.hasPlural&&d>1?1:0;f=this.units[f*8+e]||this.units[e];if(this.capitalizeUnit)f=f.capitalize();e=this.modifiers.find(function(h){return h.name=="sign"&&h.value==(g>0?1:-1)});return this[b].assign({num:d,unit:f,sign:e.src})},addFormat:function(a,b,d){var e=[],g=this;d!==k&&g.u.push(a);a=a.replace(/\s+/g,"[-,. ]*"); 91 | a=a.replace(/\{(.+?)\}/g,function(f,h){var c=h.match(/\?$/),i=h.match(/(\d)(?:-(\d))?/),m=h.match(/^\d+$/),l=h.replace(/[^a-z]+$/,""),n,r;if(l==="time"){e=e.concat(w);return c?"\\s*(?:(?:t|at |\\s+)(\\d{1,2}(?:[,.]\\d+)?):?(\\d{1,2}(?:[,.]\\d+)?)?:?(\\d{1,2}(?:[,.]\\d+)?)?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?)?":"(\\d{1,2}(?:[,.]\\d+)?):?(\\d{1,2}(?:[,.]\\d+)?)?:?(\\d{1,2}(?:[,.]\\d+)?)?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?"}if(m)n=g.optionals[m[0]];else if(g[l])n=g[l]; 92 | else if(g[l+"s"]){n=g[l+"s"];if(i){r=[];n.forEach(function(z,H){var A=H%(g.units?8:n.length);if(A>=i[1]&&A<=(i[2]||i[1]))r.push(z)});n=r}n=n.compact().join("|")}if(m)return"(?:"+n+")?";else{e.push(l);return"("+n+")"+(c?"?":"")}});M(a,e,b)}});function U(a){var b;if(q.isObject(a[0]))return a;else if(a.length==1&&q.isNumber(a[0]))return[a[0]];b={};D.each(function(d,e){b[d.a]=a[e]});return[b]} 93 | function aa(a,b){if(b!="date"&&b!="month"&&b!="year")return a;return a.replace(B,function(d){return x.indexOf(d)+1||""})}function ba(a,b){var d={},e,g;b.each(function(f,h){e=a[h+1];if(!(e===void 0||e==="")){e=aa(e.hankaku("n"),f);if(f==="year")d.t=e;g=parseFloat(e.replace(/,/,"."));d[f]=!isNaN(g)?g:e.toLowerCase()}});return d} 94 | function V(a,b){var d=new s,e=k,g,f,h,c,i,m,l;if(q.isDate(a))d=a;else if(q.isNumber(a))d=new s(a);else if(q.isObject(a)){d=(new s).set(a,j);c=a}else if(q.isString(a)){L(N(b,j));f=R(b);a=a.trim().replace(/\.+$/,"").replace(/^now$/,"");C.each(function(n){var r=a.match(n.q);if(r){h=n;c=ba(r,h.to);g=N(h.p,j);if(c.timestamp){d.setTime(0);c={milliseconds:c.timestamp};return k}if(h.h&&!q.isString(c.month)&&(q.isString(c.date)||f)){l=c.month;c.month=c.date;c.date=l}if(c.year&&c.t.length===2)c.year=((new s).getFullYear()/ 95 | 100).round()*100-(c.year/100).round()*100+c.year;if(c.month){c.month=g.getMonth(c.month);if(c.shift&&!c.unit)c.unit="year"}if(c.weekday&&c.date)delete c.weekday;else if(c.weekday){c.weekday=g.l(c.weekday);if(c.shift&&!c.unit)c.unit="week"}if(c.day&&(l=g.f[c.day])){c.day=l.value;d.resetTime();e=j}else if(c.day&&(l=g.l(c.day))>-1){delete c.day;c.weekday=l}if(c.date&&!q.isNumber(c.date))c.date=g.o(c.date);if(c.meridian)if(c.meridian==="pm"&&c.hour<12)c.hour+=12;if("offset_hours"in c||"offset_minutes"in 96 | c){c.utc=j;c.offset_minutes=c.offset_minutes||0;c.offset_minutes+=c.offset_hours*60;if(c.offset_sign==="-")c.offset_minutes*=-1;c.minute-=c.offset_minutes}if(c.unit){e=j;m=g.k(c.num);i=g.n(c.unit);if(c.shift||c.edge){m*=(l=g.f[c.shift])?l.value:0;if(i==="month"&&v(c.date)){d.set({day:c.date},j);delete c.date}if(i==="year"&&v(c.month)){d.set({month:c.month,day:c.date},j);delete c.month;delete c.date}}if(c.sign&&(l=g.f[c.sign]))m*=l.value;if(v(c.weekday)){d.set({weekday:c.weekday},j);delete c.weekday}c[i]= 97 | (c[i]||0)+m}if(c.year_sign==="-")c.year*=-1;E.slice(1,4).each(function(z,H){var A=c[z.a],S=A%1;if(S){c[E[H].a]=(S*(z.a==="second"?1E3:60)).round();c[z.a]=A|0}});return k}});if(h)if(e)d.advance(c);else if(c.utc){d.resetTime();d.setUTC(c,j)}else d.set(c,j);else d=a?new s(a):new s;if(c&&c.edge){l=g.f[c.edge];E.slice(4).each(function(n){if(v(c[n.a])){i=n.a;return k}});if(i==="year")c.d="month";else if(i==="month"||i==="week")c.d="day";d[(l.value<0?"endOf":"beginningOf")+i.capitalize()]();l.value===-2&& 98 | d.resetTime()}}return{e:d,set:c}} 99 | function W(a,b,d,e){var g,f=N(e,j),h=p(/^[A-Z]/);if(a.isValid())if(Date[b])b=Date[b];else{if(q.isFunction(b)){g=T(a.millisecondsFromNow());b=b.apply(a,g.concat(f))}}else return"Invalid Date";if(!b&&!d)b=f.outputFormat;else if(!b&&d){g=g||T(a.millisecondsFromNow());if(g[1]===0){g[1]=1;g[0]=1}return f.r(g)}G.each(function(c){b=b.replace(p("\\{("+c.b+")(\\d)?\\}",c.i?"i":""),function(i,m,l){i=c.format(a,f,l||1,m);l=m.length;var n=m.match(/^(.)\1+$/);if(c.i){if(l===3)i=i.to(3);if(n||m.match(h))i=i.capitalize()}else if(n&& 100 | !c.text)i=(q.isNumber(i)?i.pad(l):i.toString()).last(l);return i})});return b}function ca(a,b,d){var e=V(b),g=0,f=b=0,h;if(d>0){b=f=d;h=j}if(!e.e.isValid())return k;if(e.set&&e.set.d){I.each(function(i){if(i.a===e.set.d)g=i.c(e.e,a-e.e)-1});if(e.set.edge||e.set.shift)e.e["beginningOf"+e.set.d.capitalize()]();if(!h&&e.set.sign&&e.set.d!="millisecond"){b=50;f=-50}}d=a.getTime();h=e.e.getTime();var c=h+g;if(e.set&&e.set.d=="week"&&(new Date(c+1)).getHours()!=0)c+=s.DSTOffset;return d>=h-b&&d<=c+f} 101 | function X(a,b,d,e,g){if(q.isNumber(b)&&g)b={milliseconds:b};else if(q.isNumber(b)){a.setTime(b);return a}if(b.date)b.day=b.date;if(!g&&b.day===void 0&&v(b.weekday)){a["set"+(e?"UTC":"")+"Weekday"](b.weekday);b.day=a["get"+(e?"UTC":"")+"Date"](void 0);delete b.weekday}E.each(function(f){if(v(b[f.a])||v(b[f.a+"s"])){b.d=f.a;return k}else if(d&&f.a!=="week"&&f.a!=="year")a["set"+(e?"UTC":"")+f.method](f.a==="day"?1:0)});I.each(function(f){var h=f.a;f=f.method;var c=v(b[h])?b[h]:b[h+"s"];if(c!==void 0){if(g){if(h=== 102 | "week"){c=(b.day||0)+c*7;f="Date"}c=c*g+a["get"+f](void 0)}a["set"+(e?"UTC":"")+f](c);if(h==="month"){h=c;if(h<0)h+=12;h%12!=a.getMonth()&&a.setDate(0)}}});return a}function Y(a){a.addDays(4-(a.getDay()||7)).resetTime();return 1+(a.daysSince(a.clone().beginningOfYear())/7|0)}function T(a){var b,d=a.abs(),e=d,g=0;E.from(1).each(function(f,h){b=(d/f.c()*10).round()/10|0;if(b>=1){e=b;g=h+1}});return[e,g,a]}function Z(a){var b;b=q.isNumber(a[1])?U(a)[0]:a[0];return V(b,a[1]).e} 103 | function da(a,b){function d(){return(this*b).round()}function e(){return Z(arguments)[f](this)}function g(){return Z(arguments)[f](-this)}var f="add"+a.capitalize()+"s",h={};h[a]=d;h[a+"s"]=d;h[a+"Before"]=g;h[a+"sBefore"]=g;h[a+"Ago"]=g;h[a+"sAgo"]=g;h[a+"After"]=e;h[a+"sAfter"]=e;h[a+"FromNow"]=e;h[a+"sFromNow"]=e;t.extend(h)} 104 | function $(a){var b=new s(s.UTC(1999,11,31)),d={};if(!b[a]||b[a]()!=="1999-12-31T00:00:00.000Z"){d[a]=function(){return W(this.toUTC(),s.ISO8601_DATETIME)};s.extend(d,j)}}s.extend({create:function(){return Z(arguments)},now:function(){return(new s).getTime()},setLocale:function(a,b){var d=N(a,k,b);if(d){Date.currentLocale=a;L(d);return d}},getLocale:function(a){return N(a,j)},addFormat:function(a,b,d,e){M(a,b,d,e,"unshift")}},k,k); 105 | s.extend({set:function(){var a=U(arguments);return X(this,a[0],a[1])},setUTC:function(){var a=U(arguments);return X(this,a[0],a[1],j)},setWeekday:function(a){a===void 0||this.setDate(this.getDate()+a-this.getDay())},setUTCWeekday:function(a){a===void 0||this.setDate(this.getUTCDate()+a-this.getDay())},setWeek:function(a){if(a!==void 0){this.setMonth(0);this.setDate(a*7+1)}},setUTCWeek:function(a){if(a!==void 0){this.setMonth(0);this.setUTCDate(a*7+1)}},getWeek:function(){return Y(this)},getUTCWeek:function(){return Y(this.toUTC())}, 106 | getUTCOffset:function(a){var b=this.g?0:this.getTimezoneOffset(),d=a===j?":":"";if(!b&&a)return"Z";return(-b/60).round().pad(2,j)+d+(b%60).pad(2)},toUTC:function(){if(this.g)return this;var a=this.clone().addMinutes(this.getTimezoneOffset());a.g=j;return a},isUTC:function(){return this.g||this.getTimezoneOffset()===0},advance:function(){var a=U(arguments);return X(this,a[0],k,k,1,j)},rewind:function(){var a=U(arguments);return X(this,a[0],k,k,-1)},isValid:function(){return!isNaN(this.getTime())}, 107 | isAfter:function(a,b){return this.getTime()>s.create(a).getTime()-(b||0)},isBefore:function(a,b){return this.getTime()e},isLeapYear:function(){var a=this.getFullYear();return a%4===0&&a%100!==0||a%400===0},daysInMonth:function(){return 32-(new s(this.getFullYear(),this.getMonth(),32)).getDate()},format:function(a, 108 | b){return W(this,a,k,b)},relative:function(a,b){if(q.isString(a)){b=a;a=null}return W(this,a,j,b)},is:function(a,b){var d;if(q.isString(a)){a=a.trim().toLowerCase();switch(j){case a==="future":return this.getTime()>(new s).getTime();case a==="past":return this.getTime()<(new s).getTime();case a==="weekday":return this.getDay()>0&&this.getDay()<6;case a==="weekend":return this.getDay()===0||this.getDay()===6;case (d=u.weekdays.indexOf(a)%7)>-1:return this.getDay()===d;case (d=u.months.indexOf(a)%12)> 109 | -1:return this.getMonth()===d}}return ca(this,a,b)},resetTime:function(){return this.set({hour:0,minute:0,second:0,millisecond:0})},clone:function(){return new s(this.getTime())}});s.extend({iso:function(){return this.toISOString()},getWeekday:s.prototype.getDay,getUTCWeekday:s.prototype.getUTCDay});t.extend({duration:function(a){return Date.getLocale(a).duration(this)}});u=s.setLocale("en"); 110 | (function(){var a={};I.each(function(b,d){function e(i,m){return((s.create(i,m).getTime()-this.getTime())/c).round()}function g(i,m){return((this.getTime()-s.create(i,m).getTime())/c).round()}var f=b.a,h=f.capitalize(),c=b.c();a[f+"sAgo"]=e;a[f+"sUntil"]=e;a[f+"sSince"]=g;a[f+"sFromNow"]=g;a["add"+h+"s"]=function(i){var m={};m[f]=i;return this.advance(m)};da(f,c);d<3&&["Last","This","Next"].each(function(i){a["is"+i+h]=function(){return this.is(i+" "+f)}});if(d<4){a["beginningOf"+h]=function(){var i= 111 | {};switch(f){case "year":i.year=this.getFullYear();break;case "month":i.month=this.getMonth();break;case "day":i.day=this.getDate();break;case "week":i.weekday=0}return this.set(i,j)};a["endOf"+h]=function(){var i={hours:23,minutes:59,seconds:59,milliseconds:999};switch(f){case "year":i.month=11;i.day=31;break;case "month":i.day=this.daysInMonth();break;case "week":i.weekday=6}return this.set(i,j)}}});s.extend(a)})(); 112 | (function(){D=I.clone().removeAt(2);E=I.clone().reverse();var a="\\d{1,2}|"+u.months.join("|");F.each(function(b){M(b.src.replace(/\{month\}/,a)+(b.s===k?"":"\\s*(?:(?:t|at |\\s+)(\\d{1,2}(?:[,.]\\d+)?):?(\\d{1,2}(?:[,.]\\d+)?)?:?(\\d{1,2}(?:[,.]\\d+)?)?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?)?"),b.to.concat(w),"en",b.h)});M("(\\d{1,2}(?:[,.]\\d+)?):?(\\d{1,2}(?:[,.]\\d+)?)?:?(\\d{1,2}(?:[,.]\\d+)?)?(am|pm)?(?:(Z)|(?:([+-])(\\d{2})(?::?(\\d{2}))?)?)?",w)})(); 113 | (function(){var a={},b=u.weekdays.slice(0,7),d=u.months.slice(0,12);["today","yesterday","tomorrow","weekday","weekend","future","past"].concat(b).concat(d).each(function(e){a["is"+e.capitalize()]=function(){return this.is(e)}});s.extend(a)})();$("toISOString");$("toJSON"); 114 | s.extend({DSTOffset:((new s(2E3,6,1)).getTimezoneOffset()-(new s(2E3,0,1)).getTimezoneOffset())*60*1E3,INTERNATIONAL_TIME:"{h}:{mm}:{ss}",RFC1123:"{Dow}, {dd} {Mon} {yyyy} {HH}:{mm}:{ss} {tz}",RFC1036:"{Weekday}, {dd}-{Mon}-{yy} {HH}:{mm}:{ss} {tz}",ISO8601_DATE:"{yyyy}-{MM}-{dd}",ISO8601_DATETIME:"{yyyy}-{MM}-{dd}T{HH}:{mm}:{ss}.{fff}{isotz}"},k,k);})(this); 115 | -------------------------------------------------------------------------------- /sugarjs/sugartest.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /zam/js/main.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anchetaWern/tutorials/5259e6864d7f5a0a02bbb1f8158dbac90ead065d/zam/js/main.js -------------------------------------------------------------------------------- /zam/libs/twitteroauth/OAuth.php: -------------------------------------------------------------------------------- 1 | key = $key; 18 | $this->secret = $secret; 19 | $this->callback_url = $callback_url; 20 | } 21 | 22 | function __toString() { 23 | return "OAuthConsumer[key=$this->key,secret=$this->secret]"; 24 | } 25 | } 26 | 27 | class OAuthToken { 28 | // access tokens and request tokens 29 | public $key; 30 | public $secret; 31 | 32 | /** 33 | * key = the token 34 | * secret = the token secret 35 | */ 36 | function __construct($key, $secret) { 37 | $this->key = $key; 38 | $this->secret = $secret; 39 | } 40 | 41 | /** 42 | * generates the basic string serialization of a token that a server 43 | * would respond to request_token and access_token calls with 44 | */ 45 | function to_string() { 46 | return "oauth_token=" . 47 | OAuthUtil::urlencode_rfc3986($this->key) . 48 | "&oauth_token_secret=" . 49 | OAuthUtil::urlencode_rfc3986($this->secret); 50 | } 51 | 52 | function __toString() { 53 | return $this->to_string(); 54 | } 55 | } 56 | 57 | /** 58 | * A class for implementing a Signature Method 59 | * See section 9 ("Signing Requests") in the spec 60 | */ 61 | abstract class OAuthSignatureMethod { 62 | /** 63 | * Needs to return the name of the Signature Method (ie HMAC-SHA1) 64 | * @return string 65 | */ 66 | abstract public function get_name(); 67 | 68 | /** 69 | * Build up the signature 70 | * NOTE: The output of this function MUST NOT be urlencoded. 71 | * the encoding is handled in OAuthRequest when the final 72 | * request is serialized 73 | * @param OAuthRequest $request 74 | * @param OAuthConsumer $consumer 75 | * @param OAuthToken $token 76 | * @return string 77 | */ 78 | abstract public function build_signature($request, $consumer, $token); 79 | 80 | /** 81 | * Verifies that a given signature is correct 82 | * @param OAuthRequest $request 83 | * @param OAuthConsumer $consumer 84 | * @param OAuthToken $token 85 | * @param string $signature 86 | * @return bool 87 | */ 88 | public function check_signature($request, $consumer, $token, $signature) { 89 | $built = $this->build_signature($request, $consumer, $token); 90 | return $built == $signature; 91 | } 92 | } 93 | 94 | /** 95 | * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] 96 | * where the Signature Base String is the text and the key is the concatenated values (each first 97 | * encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an '&' 98 | * character (ASCII code 38) even if empty. 99 | * - Chapter 9.2 ("HMAC-SHA1") 100 | */ 101 | class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod { 102 | function get_name() { 103 | return "HMAC-SHA1"; 104 | } 105 | 106 | public function build_signature($request, $consumer, $token) { 107 | $base_string = $request->get_signature_base_string(); 108 | $request->base_string = $base_string; 109 | 110 | $key_parts = array( 111 | $consumer->secret, 112 | ($token) ? $token->secret : "" 113 | ); 114 | 115 | $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); 116 | $key = implode('&', $key_parts); 117 | 118 | return base64_encode(hash_hmac('sha1', $base_string, $key, true)); 119 | } 120 | } 121 | 122 | /** 123 | * The PLAINTEXT method does not provide any security protection and SHOULD only be used 124 | * over a secure channel such as HTTPS. It does not use the Signature Base String. 125 | * - Chapter 9.4 ("PLAINTEXT") 126 | */ 127 | class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod { 128 | public function get_name() { 129 | return "PLAINTEXT"; 130 | } 131 | 132 | /** 133 | * oauth_signature is set to the concatenated encoded values of the Consumer Secret and 134 | * Token Secret, separated by a '&' character (ASCII code 38), even if either secret is 135 | * empty. The result MUST be encoded again. 136 | * - Chapter 9.4.1 ("Generating Signatures") 137 | * 138 | * Please note that the second encoding MUST NOT happen in the SignatureMethod, as 139 | * OAuthRequest handles this! 140 | */ 141 | public function build_signature($request, $consumer, $token) { 142 | $key_parts = array( 143 | $consumer->secret, 144 | ($token) ? $token->secret : "" 145 | ); 146 | 147 | $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); 148 | $key = implode('&', $key_parts); 149 | $request->base_string = $key; 150 | 151 | return $key; 152 | } 153 | } 154 | 155 | /** 156 | * The RSA-SHA1 signature method uses the RSASSA-PKCS1-v1_5 signature algorithm as defined in 157 | * [RFC3447] section 8.2 (more simply known as PKCS#1), using SHA-1 as the hash function for 158 | * EMSA-PKCS1-v1_5. It is assumed that the Consumer has provided its RSA public key in a 159 | * verified way to the Service Provider, in a manner which is beyond the scope of this 160 | * specification. 161 | * - Chapter 9.3 ("RSA-SHA1") 162 | */ 163 | abstract class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod { 164 | public function get_name() { 165 | return "RSA-SHA1"; 166 | } 167 | 168 | // Up to the SP to implement this lookup of keys. Possible ideas are: 169 | // (1) do a lookup in a table of trusted certs keyed off of consumer 170 | // (2) fetch via http using a url provided by the requester 171 | // (3) some sort of specific discovery code based on request 172 | // 173 | // Either way should return a string representation of the certificate 174 | protected abstract function fetch_public_cert(&$request); 175 | 176 | // Up to the SP to implement this lookup of keys. Possible ideas are: 177 | // (1) do a lookup in a table of trusted certs keyed off of consumer 178 | // 179 | // Either way should return a string representation of the certificate 180 | protected abstract function fetch_private_cert(&$request); 181 | 182 | public function build_signature($request, $consumer, $token) { 183 | $base_string = $request->get_signature_base_string(); 184 | $request->base_string = $base_string; 185 | 186 | // Fetch the private key cert based on the request 187 | $cert = $this->fetch_private_cert($request); 188 | 189 | // Pull the private key ID from the certificate 190 | $privatekeyid = openssl_get_privatekey($cert); 191 | 192 | // Sign using the key 193 | $ok = openssl_sign($base_string, $signature, $privatekeyid); 194 | 195 | // Release the key resource 196 | openssl_free_key($privatekeyid); 197 | 198 | return base64_encode($signature); 199 | } 200 | 201 | public function check_signature($request, $consumer, $token, $signature) { 202 | $decoded_sig = base64_decode($signature); 203 | 204 | $base_string = $request->get_signature_base_string(); 205 | 206 | // Fetch the public key cert based on the request 207 | $cert = $this->fetch_public_cert($request); 208 | 209 | // Pull the public key ID from the certificate 210 | $publickeyid = openssl_get_publickey($cert); 211 | 212 | // Check the computed signature against the one passed in the query 213 | $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); 214 | 215 | // Release the key resource 216 | openssl_free_key($publickeyid); 217 | 218 | return $ok == 1; 219 | } 220 | } 221 | 222 | class OAuthRequest { 223 | private $parameters; 224 | private $http_method; 225 | private $http_url; 226 | // for debug purposes 227 | public $base_string; 228 | public static $version = '1.0'; 229 | public static $POST_INPUT = 'php://input'; 230 | 231 | function __construct($http_method, $http_url, $parameters=NULL) { 232 | @$parameters or $parameters = array(); 233 | $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters); 234 | $this->parameters = $parameters; 235 | $this->http_method = $http_method; 236 | $this->http_url = $http_url; 237 | } 238 | 239 | 240 | /** 241 | * attempt to build up a request from what was passed to the server 242 | */ 243 | public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) { 244 | $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") 245 | ? 'http' 246 | : 'https'; 247 | @$http_url or $http_url = $scheme . 248 | '://' . $_SERVER['HTTP_HOST'] . 249 | ':' . 250 | $_SERVER['SERVER_PORT'] . 251 | $_SERVER['REQUEST_URI']; 252 | @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; 253 | 254 | // We weren't handed any parameters, so let's find the ones relevant to 255 | // this request. 256 | // If you run XML-RPC or similar you should use this to provide your own 257 | // parsed parameter-list 258 | if (!$parameters) { 259 | // Find request headers 260 | $request_headers = OAuthUtil::get_headers(); 261 | 262 | // Parse the query-string to find GET parameters 263 | $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); 264 | 265 | // It's a POST request of the proper content-type, so parse POST 266 | // parameters and add those overriding any duplicates from GET 267 | if ($http_method == "POST" 268 | && @strstr($request_headers["Content-Type"], 269 | "application/x-www-form-urlencoded") 270 | ) { 271 | $post_data = OAuthUtil::parse_parameters( 272 | file_get_contents(self::$POST_INPUT) 273 | ); 274 | $parameters = array_merge($parameters, $post_data); 275 | } 276 | 277 | // We have a Authorization-header with OAuth data. Parse the header 278 | // and add those overriding any duplicates from GET or POST 279 | if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { 280 | $header_parameters = OAuthUtil::split_header( 281 | $request_headers['Authorization'] 282 | ); 283 | $parameters = array_merge($parameters, $header_parameters); 284 | } 285 | 286 | } 287 | 288 | return new OAuthRequest($http_method, $http_url, $parameters); 289 | } 290 | 291 | /** 292 | * pretty much a helper function to set up the request 293 | */ 294 | public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { 295 | @$parameters or $parameters = array(); 296 | $defaults = array("oauth_version" => OAuthRequest::$version, 297 | "oauth_nonce" => OAuthRequest::generate_nonce(), 298 | "oauth_timestamp" => OAuthRequest::generate_timestamp(), 299 | "oauth_consumer_key" => $consumer->key); 300 | if ($token) 301 | $defaults['oauth_token'] = $token->key; 302 | 303 | $parameters = array_merge($defaults, $parameters); 304 | 305 | return new OAuthRequest($http_method, $http_url, $parameters); 306 | } 307 | 308 | public function set_parameter($name, $value, $allow_duplicates = true) { 309 | if ($allow_duplicates && isset($this->parameters[$name])) { 310 | // We have already added parameter(s) with this name, so add to the list 311 | if (is_scalar($this->parameters[$name])) { 312 | // This is the first duplicate, so transform scalar (string) 313 | // into an array so we can add the duplicates 314 | $this->parameters[$name] = array($this->parameters[$name]); 315 | } 316 | 317 | $this->parameters[$name][] = $value; 318 | } else { 319 | $this->parameters[$name] = $value; 320 | } 321 | } 322 | 323 | public function get_parameter($name) { 324 | return isset($this->parameters[$name]) ? $this->parameters[$name] : null; 325 | } 326 | 327 | public function get_parameters() { 328 | return $this->parameters; 329 | } 330 | 331 | public function unset_parameter($name) { 332 | unset($this->parameters[$name]); 333 | } 334 | 335 | /** 336 | * The request parameters, sorted and concatenated into a normalized string. 337 | * @return string 338 | */ 339 | public function get_signable_parameters() { 340 | // Grab all parameters 341 | $params = $this->parameters; 342 | 343 | // Remove oauth_signature if present 344 | // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") 345 | if (isset($params['oauth_signature'])) { 346 | unset($params['oauth_signature']); 347 | } 348 | 349 | return OAuthUtil::build_http_query($params); 350 | } 351 | 352 | /** 353 | * Returns the base string of this request 354 | * 355 | * The base string defined as the method, the url 356 | * and the parameters (normalized), each urlencoded 357 | * and the concated with &. 358 | */ 359 | public function get_signature_base_string() { 360 | $parts = array( 361 | $this->get_normalized_http_method(), 362 | $this->get_normalized_http_url(), 363 | $this->get_signable_parameters() 364 | ); 365 | 366 | $parts = OAuthUtil::urlencode_rfc3986($parts); 367 | 368 | return implode('&', $parts); 369 | } 370 | 371 | /** 372 | * just uppercases the http method 373 | */ 374 | public function get_normalized_http_method() { 375 | return strtoupper($this->http_method); 376 | } 377 | 378 | /** 379 | * parses the url and rebuilds it to be 380 | * scheme://host/path 381 | */ 382 | public function get_normalized_http_url() { 383 | $parts = parse_url($this->http_url); 384 | 385 | $port = @$parts['port']; 386 | $scheme = $parts['scheme']; 387 | $host = $parts['host']; 388 | $path = @$parts['path']; 389 | 390 | $port or $port = ($scheme == 'https') ? '443' : '80'; 391 | 392 | if (($scheme == 'https' && $port != '443') 393 | || ($scheme == 'http' && $port != '80')) { 394 | $host = "$host:$port"; 395 | } 396 | return "$scheme://$host$path"; 397 | } 398 | 399 | /** 400 | * builds a url usable for a GET request 401 | */ 402 | public function to_url() { 403 | $post_data = $this->to_postdata(); 404 | $out = $this->get_normalized_http_url(); 405 | if ($post_data) { 406 | $out .= '?'.$post_data; 407 | } 408 | return $out; 409 | } 410 | 411 | /** 412 | * builds the data one would send in a POST request 413 | */ 414 | public function to_postdata() { 415 | return OAuthUtil::build_http_query($this->parameters); 416 | } 417 | 418 | /** 419 | * builds the Authorization: header 420 | */ 421 | public function to_header($realm=null) { 422 | $first = true; 423 | if($realm) { 424 | $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"'; 425 | $first = false; 426 | } else 427 | $out = 'Authorization: OAuth'; 428 | 429 | $total = array(); 430 | foreach ($this->parameters as $k => $v) { 431 | if (substr($k, 0, 5) != "oauth") continue; 432 | if (is_array($v)) { 433 | throw new OAuthException('Arrays not supported in headers'); 434 | } 435 | $out .= ($first) ? ' ' : ','; 436 | $out .= OAuthUtil::urlencode_rfc3986($k) . 437 | '="' . 438 | OAuthUtil::urlencode_rfc3986($v) . 439 | '"'; 440 | $first = false; 441 | } 442 | return $out; 443 | } 444 | 445 | public function __toString() { 446 | return $this->to_url(); 447 | } 448 | 449 | 450 | public function sign_request($signature_method, $consumer, $token) { 451 | $this->set_parameter( 452 | "oauth_signature_method", 453 | $signature_method->get_name(), 454 | false 455 | ); 456 | $signature = $this->build_signature($signature_method, $consumer, $token); 457 | $this->set_parameter("oauth_signature", $signature, false); 458 | } 459 | 460 | public function build_signature($signature_method, $consumer, $token) { 461 | $signature = $signature_method->build_signature($this, $consumer, $token); 462 | return $signature; 463 | } 464 | 465 | /** 466 | * util function: current timestamp 467 | */ 468 | private static function generate_timestamp() { 469 | return time(); 470 | } 471 | 472 | /** 473 | * util function: current nonce 474 | */ 475 | private static function generate_nonce() { 476 | $mt = microtime(); 477 | $rand = mt_rand(); 478 | 479 | return md5($mt . $rand); // md5s look nicer than numbers 480 | } 481 | } 482 | 483 | class OAuthServer { 484 | protected $timestamp_threshold = 300; // in seconds, five minutes 485 | protected $version = '1.0'; // hi blaine 486 | protected $signature_methods = array(); 487 | 488 | protected $data_store; 489 | 490 | function __construct($data_store) { 491 | $this->data_store = $data_store; 492 | } 493 | 494 | public function add_signature_method($signature_method) { 495 | $this->signature_methods[$signature_method->get_name()] = 496 | $signature_method; 497 | } 498 | 499 | // high level functions 500 | 501 | /** 502 | * process a request_token request 503 | * returns the request token on success 504 | */ 505 | public function fetch_request_token(&$request) { 506 | $this->get_version($request); 507 | 508 | $consumer = $this->get_consumer($request); 509 | 510 | // no token required for the initial token request 511 | $token = NULL; 512 | 513 | $this->check_signature($request, $consumer, $token); 514 | 515 | // Rev A change 516 | $callback = $request->get_parameter('oauth_callback'); 517 | $new_token = $this->data_store->new_request_token($consumer, $callback); 518 | 519 | return $new_token; 520 | } 521 | 522 | /** 523 | * process an access_token request 524 | * returns the access token on success 525 | */ 526 | public function fetch_access_token(&$request) { 527 | $this->get_version($request); 528 | 529 | $consumer = $this->get_consumer($request); 530 | 531 | // requires authorized request token 532 | $token = $this->get_token($request, $consumer, "request"); 533 | 534 | $this->check_signature($request, $consumer, $token); 535 | 536 | // Rev A change 537 | $verifier = $request->get_parameter('oauth_verifier'); 538 | $new_token = $this->data_store->new_access_token($token, $consumer, $verifier); 539 | 540 | return $new_token; 541 | } 542 | 543 | /** 544 | * verify an api call, checks all the parameters 545 | */ 546 | public function verify_request(&$request) { 547 | $this->get_version($request); 548 | $consumer = $this->get_consumer($request); 549 | $token = $this->get_token($request, $consumer, "access"); 550 | $this->check_signature($request, $consumer, $token); 551 | return array($consumer, $token); 552 | } 553 | 554 | // Internals from here 555 | /** 556 | * version 1 557 | */ 558 | private function get_version(&$request) { 559 | $version = $request->get_parameter("oauth_version"); 560 | if (!$version) { 561 | // Service Providers MUST assume the protocol version to be 1.0 if this parameter is not present. 562 | // Chapter 7.0 ("Accessing Protected Ressources") 563 | $version = '1.0'; 564 | } 565 | if ($version !== $this->version) { 566 | throw new OAuthException("OAuth version '$version' not supported"); 567 | } 568 | return $version; 569 | } 570 | 571 | /** 572 | * figure out the signature with some defaults 573 | */ 574 | private function get_signature_method(&$request) { 575 | $signature_method = 576 | @$request->get_parameter("oauth_signature_method"); 577 | 578 | if (!$signature_method) { 579 | // According to chapter 7 ("Accessing Protected Ressources") the signature-method 580 | // parameter is required, and we can't just fallback to PLAINTEXT 581 | throw new OAuthException('No signature method parameter. This parameter is required'); 582 | } 583 | 584 | if (!in_array($signature_method, 585 | array_keys($this->signature_methods))) { 586 | throw new OAuthException( 587 | "Signature method '$signature_method' not supported " . 588 | "try one of the following: " . 589 | implode(", ", array_keys($this->signature_methods)) 590 | ); 591 | } 592 | return $this->signature_methods[$signature_method]; 593 | } 594 | 595 | /** 596 | * try to find the consumer for the provided request's consumer key 597 | */ 598 | private function get_consumer(&$request) { 599 | $consumer_key = @$request->get_parameter("oauth_consumer_key"); 600 | if (!$consumer_key) { 601 | throw new OAuthException("Invalid consumer key"); 602 | } 603 | 604 | $consumer = $this->data_store->lookup_consumer($consumer_key); 605 | if (!$consumer) { 606 | throw new OAuthException("Invalid consumer"); 607 | } 608 | 609 | return $consumer; 610 | } 611 | 612 | /** 613 | * try to find the token for the provided request's token key 614 | */ 615 | private function get_token(&$request, $consumer, $token_type="access") { 616 | $token_field = @$request->get_parameter('oauth_token'); 617 | $token = $this->data_store->lookup_token( 618 | $consumer, $token_type, $token_field 619 | ); 620 | if (!$token) { 621 | throw new OAuthException("Invalid $token_type token: $token_field"); 622 | } 623 | return $token; 624 | } 625 | 626 | /** 627 | * all-in-one function to check the signature on a request 628 | * should guess the signature method appropriately 629 | */ 630 | private function check_signature(&$request, $consumer, $token) { 631 | // this should probably be in a different method 632 | $timestamp = @$request->get_parameter('oauth_timestamp'); 633 | $nonce = @$request->get_parameter('oauth_nonce'); 634 | 635 | $this->check_timestamp($timestamp); 636 | $this->check_nonce($consumer, $token, $nonce, $timestamp); 637 | 638 | $signature_method = $this->get_signature_method($request); 639 | 640 | $signature = $request->get_parameter('oauth_signature'); 641 | $valid_sig = $signature_method->check_signature( 642 | $request, 643 | $consumer, 644 | $token, 645 | $signature 646 | ); 647 | 648 | if (!$valid_sig) { 649 | throw new OAuthException("Invalid signature"); 650 | } 651 | } 652 | 653 | /** 654 | * check that the timestamp is new enough 655 | */ 656 | private function check_timestamp($timestamp) { 657 | if( ! $timestamp ) 658 | throw new OAuthException( 659 | 'Missing timestamp parameter. The parameter is required' 660 | ); 661 | 662 | // verify that timestamp is recentish 663 | $now = time(); 664 | if (abs($now - $timestamp) > $this->timestamp_threshold) { 665 | throw new OAuthException( 666 | "Expired timestamp, yours $timestamp, ours $now" 667 | ); 668 | } 669 | } 670 | 671 | /** 672 | * check that the nonce is not repeated 673 | */ 674 | private function check_nonce($consumer, $token, $nonce, $timestamp) { 675 | if( ! $nonce ) 676 | throw new OAuthException( 677 | 'Missing nonce parameter. The parameter is required' 678 | ); 679 | 680 | // verify that the nonce is uniqueish 681 | $found = $this->data_store->lookup_nonce( 682 | $consumer, 683 | $token, 684 | $nonce, 685 | $timestamp 686 | ); 687 | if ($found) { 688 | throw new OAuthException("Nonce already used: $nonce"); 689 | } 690 | } 691 | 692 | } 693 | 694 | class OAuthDataStore { 695 | function lookup_consumer($consumer_key) { 696 | // implement me 697 | } 698 | 699 | function lookup_token($consumer, $token_type, $token) { 700 | // implement me 701 | } 702 | 703 | function lookup_nonce($consumer, $token, $nonce, $timestamp) { 704 | // implement me 705 | } 706 | 707 | function new_request_token($consumer, $callback = null) { 708 | // return a new token attached to this consumer 709 | } 710 | 711 | function new_access_token($token, $consumer, $verifier = null) { 712 | // return a new access token attached to this consumer 713 | // for the user associated with this token if the request token 714 | // is authorized 715 | // should also invalidate the request token 716 | } 717 | 718 | } 719 | 720 | class OAuthUtil { 721 | public static function urlencode_rfc3986($input) { 722 | if (is_array($input)) { 723 | return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input); 724 | } else if (is_scalar($input)) { 725 | return str_replace( 726 | '+', 727 | ' ', 728 | str_replace('%7E', '~', rawurlencode($input)) 729 | ); 730 | } else { 731 | return ''; 732 | } 733 | } 734 | 735 | 736 | // This decode function isn't taking into consideration the above 737 | // modifications to the encoding process. However, this method doesn't 738 | // seem to be used anywhere so leaving it as is. 739 | public static function urldecode_rfc3986($string) { 740 | return urldecode($string); 741 | } 742 | 743 | // Utility function for turning the Authorization: header into 744 | // parameters, has to do some unescaping 745 | // Can filter out any non-oauth parameters if needed (default behaviour) 746 | public static function split_header($header, $only_allow_oauth_parameters = true) { 747 | $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; 748 | $offset = 0; 749 | $params = array(); 750 | while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { 751 | $match = $matches[0]; 752 | $header_name = $matches[2][0]; 753 | $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; 754 | if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) { 755 | $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content); 756 | } 757 | $offset = $match[1] + strlen($match[0]); 758 | } 759 | 760 | if (isset($params['realm'])) { 761 | unset($params['realm']); 762 | } 763 | 764 | return $params; 765 | } 766 | 767 | // helper to try to sort out headers for people who aren't running apache 768 | public static function get_headers() { 769 | if (function_exists('apache_request_headers')) { 770 | // we need this to get the actual Authorization: header 771 | // because apache tends to tell us it doesn't exist 772 | $headers = apache_request_headers(); 773 | 774 | // sanitize the output of apache_request_headers because 775 | // we always want the keys to be Cased-Like-This and arh() 776 | // returns the headers in the same case as they are in the 777 | // request 778 | $out = array(); 779 | foreach( $headers AS $key => $value ) { 780 | $key = str_replace( 781 | " ", 782 | "-", 783 | ucwords(strtolower(str_replace("-", " ", $key))) 784 | ); 785 | $out[$key] = $value; 786 | } 787 | } else { 788 | // otherwise we don't have apache and are just going to have to hope 789 | // that $_SERVER actually contains what we need 790 | $out = array(); 791 | if( isset($_SERVER['CONTENT_TYPE']) ) 792 | $out['Content-Type'] = $_SERVER['CONTENT_TYPE']; 793 | if( isset($_ENV['CONTENT_TYPE']) ) 794 | $out['Content-Type'] = $_ENV['CONTENT_TYPE']; 795 | 796 | foreach ($_SERVER as $key => $value) { 797 | if (substr($key, 0, 5) == "HTTP_") { 798 | // this is chaos, basically it is just there to capitalize the first 799 | // letter of every word that is not an initial HTTP and strip HTTP 800 | // code from przemek 801 | $key = str_replace( 802 | " ", 803 | "-", 804 | ucwords(strtolower(str_replace("_", " ", substr($key, 5)))) 805 | ); 806 | $out[$key] = $value; 807 | } 808 | } 809 | } 810 | return $out; 811 | } 812 | 813 | // This function takes a input like a=b&a=c&d=e and returns the parsed 814 | // parameters like this 815 | // array('a' => array('b','c'), 'd' => 'e') 816 | public static function parse_parameters( $input ) { 817 | if (!isset($input) || !$input) return array(); 818 | 819 | $pairs = explode('&', $input); 820 | 821 | $parsed_parameters = array(); 822 | foreach ($pairs as $pair) { 823 | $split = explode('=', $pair, 2); 824 | $parameter = OAuthUtil::urldecode_rfc3986($split[0]); 825 | $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : ''; 826 | 827 | if (isset($parsed_parameters[$parameter])) { 828 | // We have already recieved parameter(s) with this name, so add to the list 829 | // of parameters with this name 830 | 831 | if (is_scalar($parsed_parameters[$parameter])) { 832 | // This is the first duplicate, so transform scalar (string) into an array 833 | // so we can add the duplicates 834 | $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); 835 | } 836 | 837 | $parsed_parameters[$parameter][] = $value; 838 | } else { 839 | $parsed_parameters[$parameter] = $value; 840 | } 841 | } 842 | return $parsed_parameters; 843 | } 844 | 845 | public static function build_http_query($params) { 846 | if (!$params) return ''; 847 | 848 | // Urlencode both keys and values 849 | $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); 850 | $values = OAuthUtil::urlencode_rfc3986(array_values($params)); 851 | $params = array_combine($keys, $values); 852 | 853 | // Parameters are sorted by name, using lexicographical byte value ordering. 854 | // Ref: Spec: 9.1.1 (1) 855 | uksort($params, 'strcmp'); 856 | 857 | $pairs = array(); 858 | foreach ($params as $parameter => $value) { 859 | if (is_array($value)) { 860 | // If two or more parameters share the same name, they are sorted by their value 861 | // Ref: Spec: 9.1.1 (1) 862 | natsort($value); 863 | foreach ($value as $duplicate_value) { 864 | $pairs[] = $parameter . '=' . $duplicate_value; 865 | } 866 | } else { 867 | $pairs[] = $parameter . '=' . $value; 868 | } 869 | } 870 | // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) 871 | // Each name-value pair is separated by an '&' character (ASCII code 38) 872 | return implode('&', $pairs); 873 | } 874 | } -------------------------------------------------------------------------------- /zam/libs/twitteroauth/twitteroauth.php: -------------------------------------------------------------------------------- 1 | http_status; } 54 | function lastAPICall() { return $this->last_api_call; } 55 | 56 | /** 57 | * construct TwitterOAuth object 58 | */ 59 | function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) { 60 | $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1(); 61 | $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); 62 | if (!empty($oauth_token) && !empty($oauth_token_secret)) { 63 | $this->token = new OAuthConsumer($oauth_token, $oauth_token_secret); 64 | } else { 65 | $this->token = NULL; 66 | } 67 | } 68 | 69 | 70 | /** 71 | * Get a request_token from Twitter 72 | * 73 | * @returns a key/value array containing oauth_token and oauth_token_secret 74 | */ 75 | function getRequestToken($oauth_callback) { 76 | $parameters = array(); 77 | $parameters['oauth_callback'] = $oauth_callback; 78 | $request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters); 79 | $token = OAuthUtil::parse_parameters($request); 80 | $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); 81 | return $token; 82 | } 83 | 84 | /** 85 | * Get the authorize URL 86 | * 87 | * @returns a string 88 | */ 89 | function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) { 90 | if (is_array($token)) { 91 | $token = $token['oauth_token']; 92 | } 93 | if (empty($sign_in_with_twitter)) { 94 | return $this->authorizeURL() . "?oauth_token={$token}"; 95 | } else { 96 | return $this->authenticateURL() . "?oauth_token={$token}"; 97 | } 98 | } 99 | 100 | /** 101 | * Exchange request token and secret for an access token and 102 | * secret, to sign API calls. 103 | * 104 | * @returns array("oauth_token" => "the-access-token", 105 | * "oauth_token_secret" => "the-access-secret", 106 | * "user_id" => "9436992", 107 | * "screen_name" => "abraham") 108 | */ 109 | function getAccessToken($oauth_verifier) { 110 | $parameters = array(); 111 | $parameters['oauth_verifier'] = $oauth_verifier; 112 | $request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters); 113 | $token = OAuthUtil::parse_parameters($request); 114 | $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); 115 | return $token; 116 | } 117 | 118 | /** 119 | * One time exchange of username and password for access token and secret. 120 | * 121 | * @returns array("oauth_token" => "the-access-token", 122 | * "oauth_token_secret" => "the-access-secret", 123 | * "user_id" => "9436992", 124 | * "screen_name" => "abraham", 125 | * "x_auth_expires" => "0") 126 | */ 127 | function getXAuthToken($username, $password) { 128 | $parameters = array(); 129 | $parameters['x_auth_username'] = $username; 130 | $parameters['x_auth_password'] = $password; 131 | $parameters['x_auth_mode'] = 'client_auth'; 132 | $request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters); 133 | $token = OAuthUtil::parse_parameters($request); 134 | $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']); 135 | return $token; 136 | } 137 | 138 | /** 139 | * GET wrapper for oAuthRequest. 140 | */ 141 | function get($url, $parameters = array()) { 142 | $response = $this->oAuthRequest($url, 'GET', $parameters); 143 | if ($this->format === 'json' && $this->decode_json) { 144 | return json_decode($response); 145 | } 146 | return $response; 147 | } 148 | 149 | /** 150 | * POST wrapper for oAuthRequest. 151 | */ 152 | function post($url, $parameters = array()) { 153 | $response = $this->oAuthRequest($url, 'POST', $parameters); 154 | if ($this->format === 'json' && $this->decode_json) { 155 | return json_decode($response); 156 | } 157 | return $response; 158 | } 159 | 160 | /** 161 | * DELETE wrapper for oAuthReqeust. 162 | */ 163 | function delete($url, $parameters = array()) { 164 | $response = $this->oAuthRequest($url, 'DELETE', $parameters); 165 | if ($this->format === 'json' && $this->decode_json) { 166 | return json_decode($response); 167 | } 168 | return $response; 169 | } 170 | 171 | /** 172 | * Format and sign an OAuth / API request 173 | */ 174 | function oAuthRequest($url, $method, $parameters) { 175 | if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) { 176 | $url = "{$this->host}{$url}.{$this->format}"; 177 | } 178 | $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters); 179 | $request->sign_request($this->sha1_method, $this->consumer, $this->token); 180 | switch ($method) { 181 | case 'GET': 182 | return $this->http($request->to_url(), 'GET'); 183 | default: 184 | return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata()); 185 | } 186 | } 187 | 188 | /** 189 | * Make an HTTP request 190 | * 191 | * @return API results 192 | */ 193 | function http($url, $method, $postfields = NULL) { 194 | $this->http_info = array(); 195 | $ci = curl_init(); 196 | /* Curl settings */ 197 | curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent); 198 | curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout); 199 | curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout); 200 | curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE); 201 | curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:')); 202 | curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer); 203 | curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader')); 204 | curl_setopt($ci, CURLOPT_HEADER, FALSE); 205 | 206 | switch ($method) { 207 | case 'POST': 208 | curl_setopt($ci, CURLOPT_POST, TRUE); 209 | if (!empty($postfields)) { 210 | curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields); 211 | } 212 | break; 213 | case 'DELETE': 214 | curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE'); 215 | if (!empty($postfields)) { 216 | $url = "{$url}?{$postfields}"; 217 | } 218 | } 219 | 220 | curl_setopt($ci, CURLOPT_URL, $url); 221 | $response = curl_exec($ci); 222 | $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE); 223 | $this->http_info = array_merge($this->http_info, curl_getinfo($ci)); 224 | $this->url = $url; 225 | curl_close ($ci); 226 | return $response; 227 | } 228 | 229 | /** 230 | * Get the header info to store. 231 | */ 232 | function getHeader($ch, $header) { 233 | $i = strpos($header, ':'); 234 | if (!empty($i)) { 235 | $key = str_replace('-', '_', strtolower(substr($header, 0, $i))); 236 | $value = trim(substr($header, $i + 2)); 237 | $this->http_header[$key] = $value; 238 | } 239 | return strlen($header); 240 | } 241 | } -------------------------------------------------------------------------------- /zam/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | tests/ 17 | 18 | 19 | -------------------------------------------------------------------------------- /zam/tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | installation_housekeeping(); 20 | update_option('zam_options', array( 21 | 'zam_twitter_id' => 'Wern_Ancheta' 22 | )); 23 | } 24 | 25 | 26 | public function tearDown() { 27 | 28 | } 29 | 30 | public function test_get_tweets(){ 31 | 32 | $z = new Zam(); 33 | 34 | $tweets = $z->get_tweets(); 35 | $this->assertCount(11, $tweets); 36 | } 37 | 38 | 39 | } 40 | ?> -------------------------------------------------------------------------------- /zam/zam-options.php: -------------------------------------------------------------------------------- 1 | options = get_option('zam_options'); 9 | $this->register_settings_and_fields(); 10 | } 11 | 12 | public static function add_menu(){ 13 | 14 | add_menu_page(__('Zam', 'zam'), __('zam', 'zam'), 'manage_options', 'zam-options', array( 'zam_options', 'display_fields' )); 15 | 16 | add_submenu_page('zam-options', __('Settings', 'zam'), __('Settings', 'zam'), 'manage_options', 'zam-options', array( 'zam_options', 'display_fields' )); 17 | } 18 | 19 | public function register_settings_and_fields(){ 20 | 21 | register_setting('zam_options', 'zam_options'); 22 | add_settings_section('zam_options_main', __('Main Settings', 'zam'), array($this, 'zam_options_create'), __FILE__); 23 | 24 | $this->create_fields( 25 | __FILE__, 26 | $this, 27 | 'zam_options_main', 28 | array( 29 | array( 30 | 'id' => 'zam_twitter_id', 31 | 'label' => __('Twitter ID' , 'zam'), 32 | 'function' => 'display_twitter_id' 33 | ) 34 | ) 35 | ); 36 | } 37 | 38 | public function zam_options_create() { 39 | 40 | } 41 | 42 | public function create_fields($file, $class, $section_id, $field_data){ 43 | foreach($field_data as $field){ 44 | 45 | add_settings_field($field['id'], $field['label'], array($class, $field['function']), $file, $section_id); 46 | } 47 | } 48 | 49 | 50 | public static function display_fields(){ 51 | ?> 52 |
    53 | 54 |

    55 |
    56 | 57 | 58 | 59 |
    60 |

    61 | 62 |

    63 |
    64 | options['zam_twitter_id'])) ? $this->options['zam_twitter_id'] : ''; 69 | echo ""; 70 | } 71 | } -------------------------------------------------------------------------------- /zam/zam-tweets-widget.php: -------------------------------------------------------------------------------- 1 | __('A widget for displaying tweets', 'zam')) 15 | ); 16 | 17 | } 18 | 19 | public function form($instance){ 20 | 21 | $title = __('', 'zam'); 22 | $tweets_to_show_range = range(3, 11); 23 | $tweets_to_show = 3; 24 | 25 | if(isset($instance['title'])){ 26 | $title = esc_attr($instance['title']); 27 | } 28 | 29 | if(isset($instance['tweets_to_show'])){ 30 | $tweets_to_show = esc_attr($instance['tweets_to_show']); 31 | } 32 | ?> 33 |

    34 | 35 | 36 |

    37 | 38 |

    39 | 40 | 53 |

    54 | get_tweets(); 80 | ?> 81 |
    82 | $tweet){ 84 | ?> 85 |
  • 86 | 92 |
    93 | protocol = is_SSL() ? 'https://' : 'http://'; 20 | $this->settings = get_option('zam_options'); 21 | $this->twitter_id = (!empty($this->settings['zam_twitter_id'])) ? $this->settings['zam_twitter_id'] : ''; 22 | 23 | add_action('admin_init', function(){ 24 | new Zam_Options(); 25 | }); 26 | 27 | add_action('admin_menu', array($this, 'zam_admin_init')); 28 | 29 | add_action('widgets_init', function(){ 30 | register_widget('zam_tweets_widget'); 31 | }); 32 | 33 | add_action('save_post', array($this, 'save_tweet')); 34 | 35 | add_shortcode('zam_tweets', array($this, 'shortcode_to_tweet')); 36 | 37 | add_action('activate_zam/zam.php', array($this, 'installation_housekeeping')); 38 | 39 | register_uninstall_hook(__FILE__, array('Zam', 'uninstall_housekeeping')); 40 | 41 | } 42 | 43 | public function zam_admin_init(){ 44 | Zam_Options::add_menu(); 45 | } 46 | 47 | public function get_tweets(){ 48 | 49 | require_once 'libs/twitteroauth/twitteroauth.php'; 50 | 51 | //access the twitter API 52 | $twitterConnection = new TwitterOAuth( 53 | 'f4rQ3QIsshrq4lKEtN4dWw', //consumer key 54 | 'JJucsiYamGuLVGGfYZDw9Uj5ipnNKkfWr3q4dUjis', //consumer secret 55 | '283769265-pC9ZVicCgfodW9pzWocgq0Z4a0WiP9MjAYHEHQX2', //access token 56 | 'BM6kNo8ESEfBRSTgjvatA9EazQlEID5RM9uj7E2Jb8' //access token secret 57 | ); 58 | 59 | $twitterData = $twitterConnection->get( 60 | 'statuses/user_timeline', 61 | array( 62 | 'screen_name' => $this->twitter_id, 63 | 'count' => '11', 64 | 'exclude_replies' => true //exclude replies to a specific twitter user 65 | ) 66 | ); 67 | 68 | $tweet_text = array(); 69 | 70 | //if the request was successful 71 | if($twitterConnection->http_code == 200){ 72 | foreach($twitterData as $t){ 73 | 74 | //wrap all the url's with anchor tags 75 | $text = preg_replace( 76 | "#((http|https|ftp)://(\S*?\.\S*?))(\s|\;|\)|\]|\[|\{|\}|,|\"|'|:|\<|$|\.\s)#ie", 77 | "'$3$4'", $t->text 78 | ); 79 | 80 | $tweet_text[] = $text; 81 | } 82 | } 83 | 84 | return $tweet_text; 85 | 86 | die(); 87 | } 88 | 89 | public function save_tweet($post_id){ 90 | 91 | global $wpdb; 92 | 93 | $random_index = rand(0, 10); 94 | 95 | $post = get_post($post_id); 96 | $post_title = $post->post_title; 97 | $post_content = $post->post_content; 98 | $post_type = $post->post_type; 99 | 100 | if(!wp_is_post_revision($post_id) && $post_type == 'post'){ 101 | 102 | $pattern = '/\[zam_tweets page=([0-9])\]/'; //the general pattern for the shortcode 103 | preg_match($pattern, $post_content, $matches); 104 | if(!empty($matches)){ 105 | 106 | $page = $matches[1]; //extract the page from the matches returned 107 | 108 | $result = wp_remote_get($this->protocol . "api.twitter.com/1/statuses/user_timeline.json?screen_name=" . $this->twitter_id . "&count=11&exclude_replies=true&page=" . $page); 109 | 110 | $tweets = json_decode($result['body']); 111 | $tweet = strip_tags($tweets[$random_index]->text); 112 | 113 | $tweets_table = $wpdb->prefix . 'zam_tweets'; 114 | 115 | $wpdb->query("SELECT id FROM $tweets_table WHERE post_id = '$post_id'"); 116 | 117 | if($wpdb->num_rows == 0){ 118 | $wpdb->insert($tweets_table, array('post_id' => $post_id, 'tweet' => $tweet)); 119 | } 120 | 121 | 122 | 123 | } 124 | 125 | } 126 | 127 | } 128 | 129 | 130 | 131 | public function shortcode_to_tweet($attrs){ 132 | 133 | global $wpdb; 134 | 135 | $post_id = get_the_ID(); 136 | $post_content = get_the_content(); 137 | 138 | $pattern = '/\[zam_tweets page=([0-9])\]/'; 139 | preg_match($pattern, $post_content, $matches); 140 | 141 | if(!empty($matches)){ 142 | 143 | $tweets_table = $wpdb->prefix . 'zam_tweets'; 144 | $result = $wpdb->get_var("SELECT tweet FROM $tweets_table WHERE post_id = '$post_id'"); 145 | $content = $result; 146 | } 147 | 148 | return $content; 149 | } 150 | 151 | 152 | public function installation_housekeeping(){ 153 | 154 | global $wpdb; 155 | 156 | $tweets_table = $wpdb->prefix . 'zam_tweets'; 157 | 158 | $tweets_sql = "CREATE TABLE $tweets_table ( 159 | id INT(10) NOT NULL AUTO_INCREMENT, 160 | post_id BIGINT(20) NOT NULL, 161 | tweet VARCHAR(160) NOT NULL, 162 | PRIMARY KEY id (id) 163 | );"; 164 | 165 | require_once ABSPATH . 'wp-admin/includes/upgrade.php'; 166 | 167 | dbDelta($tweets_sql); 168 | } 169 | 170 | 171 | public static function uninstall_housekeeping(){ 172 | global $wpdb; 173 | $tweets_table = $wpdb->prefix . 'zam_tweets'; 174 | $wpdb->query("DROP TABLE $tweets_table"); 175 | delete_option('zam_options'); 176 | } 177 | 178 | 179 | } 180 | 181 | $GLOBALS['zam'] = new Zam(); 182 | ?> --------------------------------------------------------------------------------